How to use Dual channel or triple ADC?

Hi, I'm using SDK17.02 on nRF52810,and I have enabled AIN6 reading the voltage of battery successfully.

Now I need to read another voltage outside at the same time, so what should I do?

Here is the ADC code:

#include "nrf_drv_saadc.h"
#include "nrf_log.h"
#include "app_timer.h"
#include "sta_app.h"

#define BATTERY_LEVEL_MEAS_INTERVAL     APP_TIMER_TICKS(10000)              /**< Battery level measurement interval (ticks). */
static nrf_saadc_value_t m_adc_buf;
#define ADC_REF_VOLTAGE_IN_MILLIVOLTS   600                               /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
#define ADC_PRE_SCALING_COMPENSATION    6                                 /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
#define DIODE_FWD_VOLT_DROP_MILLIVOLTS  0                               /**< Typical forward voltage drop of the diode . */
#define ADC_RES_10BIT                   1024                              /**< Maximum digital value for 10-bit ADC conversion. */
/**@brief Macro to convert the result of ADC conversion in millivolts.
 *
 * @param[in]  ADC_VALUE   ADC result.
 *
 * @retval     Result converted to millivolts.
 */
#define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
        ((((ADC_VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_PRE_SCALING_COMPENSATION)

APP_TIMER_DEF(m_battery_timer_id);

/**@brief Function for handling the Battery measurement timer timeout.
 *
 * @details This function will be called each time the battery level measurement timer expires.
 *
 * @param[in] p_context  Pointer used for passing some arbitrary information (context) from the
 *                       app_start_timer() call to the timeout handler.
 */
static void m_battery_level_meas_timeout_handler(void * p_context)
{
    UNUSED_PARAMETER(p_context);
    
    ret_code_t err_code = nrf_drv_saadc_buffer_convert(&m_adc_buf, 1);
    APP_ERROR_CHECK(err_code);
    
    err_code = nrf_drv_saadc_sample();
    APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling the ADC interrupt.
 *
 * @details  This function will fetch the conversion result from the ADC, convert the value into
 *           percentage and send it to peer.
 */
void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        nrf_saadc_value_t adc_result;
        uint16_t batt_lvl_in_milli_volts;
        uint8_t percentage_batt_lvl;

        adc_result = p_event->data.done.p_buffer[0];
				
        batt_lvl_in_milli_volts =
            (ADC_RESULT_IN_MILLI_VOLTS(adc_result) + DIODE_FWD_VOLT_DROP_MILLIVOLTS)*2;
				if(batt_lvl_in_milli_volts>=4100) percentage_batt_lvl=100;
				else if((batt_lvl_in_milli_volts>=3900)&((batt_lvl_in_milli_volts<4100))) percentage_batt_lvl=75;
				else if((batt_lvl_in_milli_volts>=3700)&((batt_lvl_in_milli_volts<3900))) percentage_batt_lvl=50;
				else if((batt_lvl_in_milli_volts>=3550)&((batt_lvl_in_milli_volts<3700))) percentage_batt_lvl=25;
				else if(batt_lvl_in_milli_volts<3550) percentage_batt_lvl=0;
				m_tag_type.battery = batt_lvl_in_milli_volts;
//        NRF_LOG_INFO("Battery Level : %d [mV]  %d%%", batt_lvl_in_milli_volts,percentage_batt_lvl);
    }
    else if (p_event->type == NRF_DRV_SAADC_EVT_CALIBRATEDONE)
    {
        NRF_LOG_INFO("STA SAADC calibration complete");
    }
}
/**@brief Function for configuring ADC to do battery level conversion.
 */
void m_adc_init(void)
{
    ret_code_t err_code = nrf_drv_saadc_init(NULL, saadc_event_handler);
    APP_ERROR_CHECK(err_code);

    nrf_saadc_channel_config_t config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);

    config.burst = NRF_SAADC_BURST_ENABLED;

    err_code = nrf_drv_saadc_channel_init(0, &config);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_calibrate_offset();
    APP_ERROR_CHECK(err_code);
	
		// Create timers.
    err_code = app_timer_create(&m_battery_timer_id,
                                APP_TIMER_MODE_REPEATED,
                                m_battery_level_meas_timeout_handler);
    APP_ERROR_CHECK(err_code);
		
		// Start application timers.
    err_code = app_timer_start(m_battery_timer_id, BATTERY_LEVEL_MEAS_INTERVAL, NULL);
    APP_ERROR_CHECK(err_code);
		NRF_LOG_INFO("ADC initialized.");
}

Parents Reply Children
  • Hi, could you show me how to use dual channel in my project? I just want to read the voltage that both NRF_SAADC_INPUT_AIN6 and NRF_SAADC_INPUT_AIN7. I have tried but failed(Fatal Error).

    #include "nrf_drv_saadc.h"
    #include "nrf_log.h"
    #include "app_timer.h"
    #include "tag_app.h"
    
    #define BATTERY_LEVEL_MEAS_INTERVAL     APP_TIMER_TICKS(2000)              /**< Battery level measurement interval (ticks). */
    static nrf_saadc_value_t m_adc_buf[2];
    #define ADC_REF_VOLTAGE_IN_MILLIVOLTS   600                               /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
    #define ADC_PRE_SCALING_COMPENSATION    6                                 /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
    #define DIODE_FWD_VOLT_DROP_MILLIVOLTS  0                               /**< Typical forward voltage drop of the diode . */
    #define ADC_RES_10BIT                   1024                              /**< Maximum digital value for 10-bit ADC conversion. */
    /**@brief Macro to convert the result of ADC conversion in millivolts.
     *
     * @param[in]  ADC_VALUE   ADC result.
     *
     * @retval     Result converted to millivolts.
     */
    #define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
            ((((ADC_VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_PRE_SCALING_COMPENSATION)
    
    APP_TIMER_DEF(m_battery_timer_id);
    
    /**@brief Function for handling the Battery measurement timer timeout.
     *
     * @details This function will be called each time the battery level measurement timer expires.
     *
     * @param[in] p_context  Pointer used for passing some arbitrary information (context) from the
     *                       app_start_timer() call to the timeout handler.
     */
    static void m_battery_level_meas_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        ret_code_t err_code;
    	
        err_code = nrf_drv_saadc_buffer_convert(&m_adc_buf[0], 1);
        APP_ERROR_CHECK(err_code);
    
    		err_code = nrf_drv_saadc_buffer_convert(&m_adc_buf[1], 1);
        APP_ERROR_CHECK(err_code);
        
        err_code = nrf_drv_saadc_sample();
        APP_ERROR_CHECK(err_code);
    }
    /**@brief Function for handling the ADC interrupt.
     *
     * @details  This function will fetch the conversion result from the ADC, convert the value into
     *           percentage and send it to peer.
     */
    void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
    {
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
            nrf_saadc_value_t adc_result[2];
    
            uint16_t batt_lvl_in_milli_volts;
    				uint16_t charge_lvl_in_milli_volts;
            uint8_t percentage_batt_lvl;
    
            adc_result[0] = p_event->data.done.p_buffer[0];
    				adc_result[1] = p_event->data.done.p_buffer[1];
    			
            batt_lvl_in_milli_volts =
                (ADC_RESULT_IN_MILLI_VOLTS(adc_result[0]) + DIODE_FWD_VOLT_DROP_MILLIVOLTS)*2;
    				if(batt_lvl_in_milli_volts>=4100) percentage_batt_lvl=100;
    				else if((batt_lvl_in_milli_volts>=3900)&((batt_lvl_in_milli_volts<4100))) percentage_batt_lvl=75;
    				else if((batt_lvl_in_milli_volts>=3700)&((batt_lvl_in_milli_volts<3900))) percentage_batt_lvl=50;
    				else if((batt_lvl_in_milli_volts>=3550)&((batt_lvl_in_milli_volts<3700))) percentage_batt_lvl=25;
    				else if(batt_lvl_in_milli_volts<3550) percentage_batt_lvl=0;
    				m_tag_type.battery = batt_lvl_in_milli_volts;
    //        NRF_LOG_INFO("Battery Level : %d [mV]  %d%%", batt_lvl_in_milli_volts,percentage_batt_lvl);
        }
        else if (p_event->type == NRF_DRV_SAADC_EVT_CALIBRATEDONE)
        {
            NRF_LOG_INFO("TAG SAADC calibration complete");
        }
    }
    /**@brief Function for configuring ADC to do battery level conversion.
     */
    void m_adc_init(void)
    {
        ret_code_t err_code = nrf_drv_saadc_init(NULL, saadc_event_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_saadc_channel_config_t config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);
    		config.burst = NRF_SAADC_BURST_ENABLED;
    	
    		nrf_saadc_channel_config_t config_charge =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
    		config_charge.burst = NRF_SAADC_BURST_ENABLED;
    	
        err_code = nrf_drv_saadc_channel_init(0, &config);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_calibrate_offset();
        APP_ERROR_CHECK(err_code);
    	
    		// Create timers.
        err_code = app_timer_create(&m_battery_timer_id,
                                    APP_TIMER_MODE_REPEATED,
                                    m_battery_level_meas_timeout_handler);
        APP_ERROR_CHECK(err_code);
    		
    		// Start application timers.
        err_code = app_timer_start(m_battery_timer_id, BATTERY_LEVEL_MEAS_INTERVAL, NULL);
        APP_ERROR_CHECK(err_code);
    		NRF_LOG_INFO("ADC initialized.");
    }
    
    

Related