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

Accurate ADC measurement without the Soft Device

I'd like to measure the voltage of a lithium ion battery every minute or so in a way that's highly accurate. I need to do this without using the Soft Device because a) I need all the memory I can get for logging the voltages and b) what I'm really testing is a generator that's charging my battery so I want the power consumption of my board while I'm testing to be fairly low.

There's plenty of discussion about using the high frequency clock with the soft device to get an accurate ADC reading here:

devzone.nordicsemi.com/.../adc-softdevice-sample-rate-on-nrf51822

That code does this ten times a second:

static void adc_sampling_timeout_handler(void * p_context)
{
	uint32_t p_is_running = 0;
		
	sd_clock_hfclk_request();
	while(! p_is_running) {  							//wait for the hfclk to be available
		sd_clock_hfclk_is_running((&p_is_running));
	}               
	nrf_gpio_pin_toggle(NRF6310_LED_2);		//Toggle LED2 to indicate start of sampling
	NRF_ADC->TASKS_START = 1;							//Start ADC sampling
}

and then releases the clock at the end of the IRQ handler:

sd_clock_hfclk_release();

My question is, how do I do the same thing but without use of the Soft Device?

Parents
  • Hi Håkon,

    I think what you've addressed above is helping reduce power consumption while reading the ADC. But that only takes a fraction of a second. What about reducing consumption in between samples? (I sample once every 30s for now.)

    I've tried using NRF_TIMER0->TASKS_SHUTDOWN for this and it seems to work but I want to check my approach. My main() looks like this (note the return from main, which seems a bit weird).

    	uint32_t err_code;
    	app_timer_id_t timer_id;
    
    	timers_init();
    	battery_level_init();
    
    	start_clock();
    
    	err_code = app_timer_create(&timer_id, APP_TIMER_MODE_REPEATED, generator_test_timeout_handler);
    	APP_ERROR_CHECK(err_code);
    
    	err_code = app_timer_start(timer_id, APP_TIMER_TICKS(30000, 0), NULL);
    	APP_ERROR_CHECK(err_code);
    
    	// Shutdown and wait for timer to timeout.
    	NRF_TIMER0->TASKS_SHUTDOWN = 1;
    	return 0;
    

    battery_level_init() sets up the ADC. start_clock() starts the LF clock explicitly, since we're not using the Soft Device. The timeout handler is simply:

    void generator_test_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        battery_level_read();
    }
    

    in battery_level_read() I use your "safest approach" above.

    Seems to work, even with the debugger, but I haven't yet tested the power consumption. Does all this seem OK to you?

  • Hi Eliot,

    Using the RTC (app_timer) to create this 30 sec tick is the way to do it, especially when thinking of current consumption.

    Returns from main aren't recommended in embedded applications. I do not know on which level you're calling this return, but if this is set in the main-while loop, then you'll return to an unknown state. I assume this is some sort of function call, since there's no sleep-call at the end of it?

Reply
  • Hi Eliot,

    Using the RTC (app_timer) to create this 30 sec tick is the way to do it, especially when thinking of current consumption.

    Returns from main aren't recommended in embedded applications. I do not know on which level you're calling this return, but if this is set in the main-while loop, then you'll return to an unknown state. I assume this is some sort of function call, since there's no sleep-call at the end of it?

Children
No Data
Related