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