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

nRF52810 ain4 pin (battery level)

Hi,

I'm using nRF52810.

And i'm trying to measure battery level using saadc.

The problem is saadc result is not accuracy.

When battery voltage is 3.3v, saadc value is 0x0D4 ~ 0x200.

When battery voltage is 4.2v, saadc value is also 0x0D2 ~ 0x212.  

I'm using P0.28 for measuring battery level.

What's the problem?

This is my schematic for saadc.

And, this is my code.

#include <stdio.h>
#include "app_error.h"
#include "nrf_twi_mngr.h"
#include "nrf_drv_gpiote.h"
#include "nrf_delay.h"


 //for checking battery
#include "nrf_drv_saadc.h"
#include "nrf_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_timer.h"

#include "bq24091.h"


volatile uint8_t batt_chg_state = NO_CHG;



//battery

#define SAMPLES_IN_BUFFER 4
static nrf_saadc_value_t m_buffer_pool[4][SAMPLES_IN_BUFFER];
static nrf_drv_timer_t timer1 = NRF_DRV_TIMER_INSTANCE(1);
static nrf_ppi_channel_t ppi_channel1;  

static uint8_t vBatCheckFlag = false;





void vBatChecker_init(void);
void vBatCheck_event_enable(uint8_t enable);



uint8_t getChgPinState(void){
	return nrf_gpio_pin_read(BQ24091_CHGB);
}

uint8_t getPgPinState(void){
	return nrf_gpio_pin_read(BQ24091_PGB);
}


void checkChargingState(void){
	if(getChgPinState()){
		if(!getPgPinState()){
			batt_chg_state = CHG_COMPLETE;
		}else{
			batt_chg_state = NO_CHG;
		}
	}
	else{
		if(!getPgPinState()){
			batt_chg_state = CHARGING;
		}
	}
}

void chg_event(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action){
	checkChargingState();
}

void bq24091_init(void){
	ret_code_t err_code;

	//set msp drdy pin for input pin
	//nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
	//in_config.pull = NRF_GPIO_PIN_PULLUP;
	//APP_ERROR_CHECK(nrf_drv_gpiote_in_init(BQ24091_CHGB, &in_config, chg_event));  
	
	//nrf_drv_gpiote_in_event_enable(BQ24091_CHGB, true);
	
	//in_config.pull = NRF_GPIO_PIN_PULLUP;
	//APP_ERROR_CHECK(nrf_drv_gpiote_in_init(BQ24091_PGB, &in_config, pg_event)); 
	
	//nrf_drv_gpiote_in_event_enable(BQ24091_PGB, true);
	
	vBatChecker_init();
	vBatCheck_event_enable(true);
}







void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
	uint16_t adc_sum_value = 0;
	uint16_t adc_average_value=0;
	     
	if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
	{
		ret_code_t err_code;     				
		int i;     
 
		err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
		APP_ERROR_CHECK(err_code);
	}
}

void saadc_init()
{
	ret_code_t err_code;
	nrf_drv_saadc_config_t saadc_config;
	nrf_saadc_channel_config_t channel_config =  NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
		
	channel_config.gain = NRF_SAADC_GAIN1_4;
	channel_config.reference = NRF_SAADC_REFERENCE_VDD4;
	channel_config.acq_time = NRF_SAADC_ACQTIME_20US;
	
	//Configure SAADC
	saadc_config.low_power_mode = true;                                                   //Enable low power mode.
	saadc_config.resolution = NRF_SAADC_RESOLUTION_14BIT;                                 //Set SAADC resolution to 12-bit. This will make the SAADC output values from 0 (when input voltage is 0V) to 2^12=4096 (when input voltage is 3.6V for channel gain setting of 1/6).
	saadc_config.oversample = NRF_SAADC_OVERSAMPLE_4X;                                           //Set oversample to 4x. This will make the SAADC output a single averaged value when the SAMPLE task is triggered 4 times.
	saadc_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;  
		
	err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);	
	APP_ERROR_CHECK(err_code);
	
	err_code = nrf_drv_saadc_channel_init(0, &channel_config);
	APP_ERROR_CHECK(err_code);
	
	err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
	APP_ERROR_CHECK(err_code);
	
	err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
	APP_ERROR_CHECK(err_code);
}



void timer_handler(nrf_timer_event_t event_type, void * p_context)
{
	__NOP;
}

static void saadc_sampling_event_init(void){
	uint32_t err_code = NRF_SUCCESS;
	
	err_code = nrf_drv_ppi_init();
	APP_ERROR_CHECK(err_code);
	
	nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
	timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
	err_code = nrf_drv_timer_init(&timer1, &timer_cfg, timer_handler);
	APP_ERROR_CHECK(err_code);

	uint32_t ticks = nrf_drv_timer_ms_to_ticks(&timer1, 500); //tick every 500ms (first time only)
	nrf_drv_timer_extended_compare(&timer1, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);

	err_code = nrf_drv_ppi_channel_alloc(&ppi_channel1);
	APP_ERROR_CHECK(err_code);
	err_code = nrf_drv_ppi_channel_assign(ppi_channel1, nrf_drv_timer_event_address_get(&timer1, NRF_TIMER_EVENT_COMPARE0), nrf_drv_saadc_sample_task_get());
	APP_ERROR_CHECK(err_code);
}

void vBatCheck_event_enable(uint8_t enable)
{
	ret_code_t err_code;
	
	if(enable){
		err_code = nrf_drv_ppi_channel_enable(ppi_channel1); // enable both configured PPI channels
		APP_ERROR_CHECK(err_code);
		
		nrf_drv_timer_enable(&timer1);//enable battery timer
	}else{
		err_code = nrf_drv_ppi_channel_disable(ppi_channel1); // enable both configured PPI channels
		APP_ERROR_CHECK(err_code);
		
		nrf_drv_timer_disable(&timer1);//enable battery timer
	}	
}


void vBatChecker_init(void){
	saadc_init();      	
	saadc_sampling_event_init();
	
	vBatCheckFlag = true;
}



Related