Hello
I am using nrf52840 chip. I am having trouble configuring SAADC to read analogue input on two channels (one signal is VDD of the chip). I have already searched the forum and came across the thread in the description. I had no problems using SAADC while i was reading one channel, however I need to expand my code to read two channels. When i tried to upgrade my code, the program began to freeze. I do not know where the problem is, so i hope someone can help me to spot the error. I have tried to upgrade my code similar to the code in the thread, but ended up failing. In the description are the header file and the cpp file containing the class I have made. I need to make functions get_analogue_input() and get_VDD() to work.
Thank you for your time,
Best regards
thread: https://devzone.nordicsemi.com/f/nordic-q-a/14938/nrf52-reading-ain0-to-ain4-ain4-fails
/*************************************************************************************************//** ** ** @file EODRV_Saadc.h ** Header file for class CEODRV_Saadc ** ** @addtogroup DriverObjects ** CEODRV_Saadc ** *****************************************************************************************************/ #ifndef _EODRV_SAADC_H #define _EODRV_SAADC_H #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include <math.h> #include "EODRV.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" //analogue input pins on the board: #define ANALOGUE_PIN_0 0 #define ANALOGUE_PIN_1 1 #define ANALOGUE_PIN_2 2 #define ANALOGUE_PIN_3 3 #define ANALOGUE_PIN_4 4 #define ANALOGUE_PIN_5 5 #define ANALOGUE_PIN_6 6 //the channel used for the analogue to digital conversion is channel 0 #define SAADC_CHANNEL_0 0 #define SAADC_CHANNEL_1 1 //number of analogue pins that are being sampled #define NUMBER_OF_SAMPLED_CHANNELS 2 /* The DEVIDE_CONSTANT depends on V(p), V(n), gain, reference and resolution and its value must be changed if any of the listed parameters are changed. */ #define DEVIDE_CONSTANT 4551.1f //other macros #define START 1 #define STOP 0 #define IS_NOT_STARTED 0 #define STOP_TASK_EVENT 1 #define IS_NOT_STOPEED 0 #define TASK_EVENT_IS_STOPPED 0 #define VDD_INDEX 1 /** * @brief Class for object CEODRV_Saadc, from Driver objects group */ class CEODRV_Saadc : public CEODRV { private: //atributes volatile unsigned short result[NUMBER_OF_SAMPLED_CHANNELS]; //a buffer in which will be stored the //values of SAADC conversions before being //devided by the formula float voltage_on_the_saadc_pin[NUMBER_OF_SAMPLED_CHANNELS]; //this is the input voltage of the analog pin, that is the //result of SAADC conversion public: //constructior CEODRV_Saadc(); //methods void Init (void); void activate_saadc_high_frequency_clock (void); //Start HFCLK (HIGH FREQUENCY CLOCK) from crystal oscillator, //this will give the SAADC high accuracy void configure_saadc_channel (unsigned long channel, unsigned long gain, unsigned long mode, unsigned long refsel, unsigned long resn, unsigned long resp, unsigned long tacq, unsigned long pselp, unsigned long pseln, unsigned long pselp_position); void configure_saadc_resolution (unsigned long resolution); void configure_saadc_14_bit_resolution (void); void configre_saadc_result_buffer (void); void configure_saadc_sampling_mode (unsigned long sampling_mode); void configure_saadc_sampling_mode_as_task_sampling_mode (void); void enable_saadc (void); void disable_saadc (void); void calibrate_saadc (void); void start_saadc_task_event (void); void make_a_sample_and_put_it_in_the_result_buffer (void); float* calculate_saadc_input_voltage (void); void stop_saadc_task_event (void); float get_voltage_on_the_saadc_pin (uint8_t index); void make_saadc_sample (void); float make_saadc_sample_and_get_the_value_of_volts_on_the_saadc_pin (uint8_t index); float get_analogue_input (void); float get_VDD (void); // Overloaded virtual functions ------------------------------- // ------------------------------------------------------------ }; #endif // #ifndef _EODRV_SAADC_H
/*************************************************************************************************//** ** ** @file EODRV_Saadc.cpp ** Implementation file for class CEODRV_Saadc ** *****************************************************************************************************/ //#include "EmbeddedStd.h" #include "EODRV_Saadc.h" /*************************************************************************************************//** ** ** @brief Constructor for CEODRV_Saadc class ** *****************************************************************************************************/ volatile unsigned short result[NUMBER_OF_SAMPLED_CHANNELS]; float voltage_on_the_saadc_pin[NUMBER_OF_SAMPLED_CHANNELS]; CEODRV_Saadc::CEODRV_Saadc() : CEODRV() { for(int i = 0; i < NUMBER_OF_SAMPLED_CHANNELS; i++){ result[i] = 0; voltage_on_the_saadc_pin[i] = 0; } } void CEODRV_Saadc::Init(void){ activate_saadc_high_frequency_clock(); configure_saadc_channel(SAADC_CHANNEL_0, SAADC_CH_CONFIG_GAIN_Gain1_6, SAADC_CH_CONFIG_MODE_SE, SAADC_CH_CONFIG_REFSEL_Internal, SAADC_CH_CONFIG_RESN_Bypass, SAADC_CH_CONFIG_RESP_Bypass, SAADC_CH_CONFIG_TACQ_3us, SAADC_CH_PSELP_PSELP_AnalogInput3, SAADC_CH_PSELN_PSELN_NC, SAADC_CH_PSELP_PSELP_Pos); configure_saadc_channel(SAADC_CHANNEL_1, SAADC_CH_CONFIG_GAIN_Gain1_6, SAADC_CH_CONFIG_MODE_SE, SAADC_CH_CONFIG_REFSEL_Internal, SAADC_CH_CONFIG_RESN_Bypass, SAADC_CH_CONFIG_RESP_Bypass, SAADC_CH_CONFIG_TACQ_3us, SAADC_CH_PSELP_PSELP_AnalogInput4, SAADC_CH_PSELN_PSELN_NC, SAADC_CH_PSELP_PSELP_VDD); configure_saadc_14_bit_resolution(); configre_saadc_result_buffer(); configure_saadc_sampling_mode_as_task_sampling_mode(); enable_saadc(); } void CEODRV_Saadc::activate_saadc_high_frequency_clock(void){ NRF_CLOCK->TASKS_HFCLKSTART = START; while (NRF_CLOCK->EVENTS_HFCLKSTARTED == IS_NOT_STARTED); NRF_CLOCK->EVENTS_HFCLKSTARTED = STOP; } void CEODRV_Saadc::configure_saadc_channel(unsigned long channel, unsigned long gain, unsigned long mode, unsigned long refsel, unsigned long resn, unsigned long resp, unsigned long tacq, unsigned long pselp, unsigned long pseln, unsigned long pselp_position){ NRF_SAADC->CH[channel].CONFIG = (gain << SAADC_CH_CONFIG_GAIN_Pos) | (mode << SAADC_CH_CONFIG_MODE_Pos) | (refsel << SAADC_CH_CONFIG_REFSEL_Pos) | (resn << SAADC_CH_CONFIG_RESN_Pos) | (resp << SAADC_CH_CONFIG_RESP_Pos) | (tacq << SAADC_CH_CONFIG_TACQ_Pos); NRF_SAADC->CH[channel].PSELP = pselp << pselp_position; NRF_SAADC->CH[channel].PSELN = pseln << SAADC_CH_PSELN_PSELN_Pos; } void CEODRV_Saadc::configure_saadc_resolution(unsigned long resolution){ NRF_SAADC->RESOLUTION = resolution << SAADC_RESOLUTION_VAL_Pos; } void CEODRV_Saadc::configure_saadc_14_bit_resolution(void){ configure_saadc_resolution(SAADC_RESOLUTION_VAL_14bit); } void CEODRV_Saadc::configre_saadc_result_buffer(void){ NRF_SAADC->RESULT.MAXCNT = NUMBER_OF_SAMPLED_CHANNELS; NRF_SAADC->RESULT.PTR = (uint32_t)&result[0]; } void CEODRV_Saadc::configure_saadc_sampling_mode(unsigned long sampling_mode){ NRF_SAADC->SAMPLERATE = sampling_mode << SAADC_SAMPLERATE_MODE_Pos; } void CEODRV_Saadc::configure_saadc_sampling_mode_as_task_sampling_mode(void){ configure_saadc_sampling_mode(SAADC_SAMPLERATE_MODE_Task); } void CEODRV_Saadc::enable_saadc(void){ NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos; } void CEODRV_Saadc::disable_saadc(void){ NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Disabled << SAADC_ENABLE_ENABLE_Pos; } void CEODRV_Saadc::calibrate_saadc(void){ NRF_SAADC->TASKS_CALIBRATEOFFSET = START; while (NRF_SAADC->EVENTS_CALIBRATEDONE == IS_NOT_STARTED); NRF_SAADC->EVENTS_CALIBRATEDONE = STOP; while (NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy <<SAADC_STATUS_STATUS_Pos)); } void CEODRV_Saadc::start_saadc_task_event(void){ NRF_SAADC->TASKS_START = START; while (NRF_SAADC->EVENTS_STARTED == IS_NOT_STARTED); NRF_SAADC->EVENTS_STARTED = STOP; } void CEODRV_Saadc::make_a_sample_and_put_it_in_the_result_buffer(void){ NRF_SAADC->TASKS_SAMPLE = START; while (NRF_SAADC->EVENTS_END == IS_NOT_STARTED); NRF_SAADC->EVENTS_END = STOP; } float* CEODRV_Saadc::calculate_saadc_input_voltage(void){ //Convert the result to voltage // Result = [V(p) - V(n)] * GAIN/REFERENCE * 2^(RESOLUTION) // Result = (VDD - 0) * ((1/6) / 0.6) * 2^14 // VDD = Result / 4551.1 for(int i=0;i<NUMBER_OF_SAMPLED_CHANNELS;i++){ voltage_on_the_saadc_pin[i] =(float)result[i]/DEVIDE_CONSTANT; } return &voltage_on_the_saadc_pin[0]; } void CEODRV_Saadc::stop_saadc_task_event(void){ NRF_SAADC->TASKS_STOP = STOP_TASK_EVENT; while (NRF_SAADC->EVENTS_STOPPED == IS_NOT_STOPEED){}; NRF_SAADC->EVENTS_STOPPED = TASK_EVENT_IS_STOPPED; } float CEODRV_Saadc::get_voltage_on_the_saadc_pin(uint8_t index){ return voltage_on_the_saadc_pin[index]; } void CEODRV_Saadc::make_saadc_sample(void){ calibrate_saadc(); // Start the SAADC and wait for the started event. start_saadc_task_event(); // Do a SAADC sample, will put the result in the configured RAM buffer. make_a_sample_and_put_it_in_the_result_buffer(); calculate_saadc_input_voltage(); stop_saadc_task_event(); } float CEODRV_Saadc::make_saadc_sample_and_get_the_value_of_volts_on_the_saadc_pin(uint8_t index){ make_saadc_sample(); return get_voltage_on_the_saadc_pin(index); } float CEODRV_Saadc::get_analogue_input(index){ return make_saadc_sample_and_get_the_value_of_volts_on_the_saadc_pin(0); } float CEODRV_Saadc::get_VDD(void){ return make_saadc_sample_and_get_the_value_of_volts_on_the_saadc_pin(VDD_INDEX); }