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