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

SAADC Advanced mode with PPI (NRFX_SAADC_V2)

How start sampling by timer with PPI?

#define SAADC_CHANNEL_COUNT   4
#define SAADC_BUF_SIZE   SAADC_CHANNEL_COUNT * 8
#define SAADC_SAMPLE_INTERVAL_MS 250

static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
static volatile bool is_ready = true;
static nrf_saadc_value_t samples[SAADC_BUF_SIZE];
static nrfx_saadc_channel_t channels[SAADC_CHANNEL_COUNT] = {NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN0, 0),
                                                             NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN1, 1),
                                                             NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN2, 2),
                                                             NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN3, 3)};
static nrf_ppi_channel_t     m_ppi_channel;
static uint32_t              m_adc_evt_counter;

APP_TIMER_DEF(m_sample_timer_id);     /**< Handler for repeated timer used to blink LED 1. */
 
static void event_handler(nrfx_saadc_evt_t const * p_event)
{
    ret_code_t err_code;
    switch (p_event->type)
    {
        case NRFX_SAADC_EVT_FINISHED:
            for(int i = 0; i < p_event->data.done.size; i++)
            {
                NRF_LOG_INFO("CH%d: %d", i, p_event->data.done.p_buffer[i]);
            }

            is_ready = true;
            nrf_gpio_pin_toggle(LED_ST_B);
            break;
        case NRFX_SAADC_EVT_BUF_REQ:
            err_code = nrfx_saadc_buffer_set(samples, SAADC_BUF_SIZE);
            APP_ERROR_CHECK(err_code);
            //buf_to_load++;
            break;
        default:
            break;
    }

    /* Applying workaround from Errata 212, otherwise current is stuck at 4-500uA during sleep after first sample. */
    volatile uint32_t temp1;
    volatile uint32_t temp2;
    volatile uint32_t temp3;

    temp1 = *(volatile uint32_t *)0x40007640ul;
    temp2 = *(volatile uint32_t *)0x40007644ul;
    temp3 = *(volatile uint32_t *)0x40007648ul;

    *(volatile uint32_t *)0x40007FFCul = 0ul; 
    *(volatile uint32_t *)0x40007FFCul; 
    *(volatile uint32_t *)0x40007FFCul = 1ul;

    *(volatile uint32_t *)0x40007640ul = temp1;
    *(volatile uint32_t *)0x40007644ul = temp2;
    *(volatile uint32_t *)0x40007648ul = temp3;
}

void saadc_sampling_event_init(void)
{
    ret_code_t err_code;

    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(&m_timer, &timer_cfg, timer_handler);
    APP_ERROR_CHECK(err_code);

    /* setup m_timer for compare event every 10ms */
    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 100);
    //uint32_t ticks = nrf_drv_timer_us_to_ticks(&m_timer, 10);
    nrf_drv_timer_extended_compare(&m_timer,
                                   NRF_TIMER_CC_CHANNEL0,
                                   ticks,
                                   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                   false);
    nrf_drv_timer_enable(&m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
                                                                                NRF_TIMER_CC_CHANNEL0);
    uint32_t saadc_sample_task_addr   = NRF_SAADC_TASK_SAMPLE;

    /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                          timer_compare_event_addr,
                                          saadc_sample_task_addr);
    APP_ERROR_CHECK(err_code);
}
 
int main(void)
{
    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);                       //Configure Logging. LOGGING is used to show the SAADC sampled result. Default is UART, but RTT can be configured in sdk_config.h
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    NRF_LOG_INFO("nrfx_saadc_api2 simple SAADC Low Power Example.");	

    err_code = nrfx_saadc_init(NRFX_SAADC_CONFIG_IRQ_PRIORITY);
    APP_ERROR_CHECK(err_code);
 
    err_code = nrfx_saadc_channels_config(channels, SAADC_CHANNEL_COUNT);
    APP_ERROR_CHECK(err_code);

    nrfx_saadc_adv_config_t config = {
        .oversampling      = NRF_SAADC_OVERSAMPLE_8X,       // oversample.
        .burst             = NRF_SAADC_BURST_ENABLED,       // burst.
        .internal_timer_cc = 0,                             // Sample 0.
        .start_on_end      = true,                          // Latch next buffer at END event in interrupt.
    };
    err_code = nrfx_saadc_advanced_mode_set((1<<0|1<<1|1<<2|1<<3),
                                          NRF_SAADC_RESOLUTION_12BIT,
                                          &config,
                                          event_handler);
    
    APP_ERROR_CHECK(err_code);
    
    err_code = nrfx_saadc_buffer_set(samples, SAADC_BUF_SIZE);
    APP_ERROR_CHECK(err_code);

    //timers_init();
    saadc_sampling_event_init();


    err_code = nrfx_saadc_mode_trigger();
    APP_ERROR_CHECK(err_code);

    while (1)
    {
        while(NRF_LOG_PROCESS() != NRF_SUCCESS);
        __WFE();
    }
    
}


/** @} */

Parents
  • Hello,

    Sorry for my late reply.

    You will need to enable your PPI channel as well, currently you are just configuring and initializing it.
    You should also use nrf_saadc_task_address_get to acquire the address of the SAADC SAMPLE task, I do not think you can do it as you currently are doing it.
    What are you seeing when you program you device with the code above?

    Please make these changes, and let me know if your application behaves as expected.

    Best regards,
    Karl

  • Hi Karl,

    When I use SAADC with PPI, I measured the power using PPK on 52833 DK and get about 700uA background current.

    But when I use SAADC with RTC(sample per 10ms), the background current is very low, it's about 40uA.

    NOTE: In this case, I don't use double buffering, I set up buffer just before sampling in RTC_handler.

    If I use SAADC with PPI, how should I do, to reduce the background current.

    Why the background current is so high when I use PPI to trigger SAADC sample?

    Since Double buffer & DMA?

    Thanks.

Reply
  • Hi Karl,

    When I use SAADC with PPI, I measured the power using PPK on 52833 DK and get about 700uA background current.

    But when I use SAADC with RTC(sample per 10ms), the background current is very low, it's about 40uA.

    NOTE: In this case, I don't use double buffering, I set up buffer just before sampling in RTC_handler.

    If I use SAADC with PPI, how should I do, to reduce the background current.

    Why the background current is so high when I use PPI to trigger SAADC sample?

    Since Double buffer & DMA?

    Thanks.

Children
  • Hello,

    lvpeng said:

    If I use SAADC with PPI, how should I do, to reduce the background current.

    Why the background current is so high when I use PPI to trigger SAADC sample?

    PPI is only the peripheral that connects an event to a task - what is the event you are using to trigger the SAMPLE_TASK in the 'with PPI' setup?
    For example, if you are using the HFCLK to generate these events (such as with a TIMER instance), the HFCLK will be running and thus increasing your current consumption.
    EasyDMA is always in use when the SAADC is started, and that will indeed increase your base level current consumption.
    Since you are only sampling once each 10 ms (if I have understood your intentions correctly) you could turn off the SAADC between each sample, to reduce this background current. Keep in mind that the increased current draw from easyDMA will be present whenever it is in use - and it might also be in use by another peripheral at this time, not just the SAADC. So, to reduce this current consumption you would have to make sure that easyDMA is not in use by any of your peripherals.

    For future reference I recommend that you open a separate ticket for any questions that do not directly relate to a previous question, or that is diverging from the original ticket. This is recommended so that the forum can remain tidy and easy to navigate for other users.

    Best regards,
    Karl

  • Hi Karl,

    Thanks for your reply.

    If I use a TIMER-EVENT trigger SAMPLE-TASK each 10ms(use PPI connects EVENTand TASK) to sampling. Can I turn off the SAADC?

    If I turn off the SAADC in SAADC_CALLBACK function, how should I turn on again?

    Thanks.

  • lvpeng said:
    Thanks for your reply.

    No problem at all, I am happy to help!

    lvpeng said:
    If I use a TIMER-EVENT trigger SAMPLE-TASK each 10ms(use PPI connects EVENTand TASK) to sampling.

    The TIMER peripheral will use the high-frequency clock, which will draw considerably more power than the RTC or LFCLK.
    To save power on your 10 ms timer, you should use the RTC or another non-HFCLK clock source.
    Please change your clock source, and let me know how much your baseline current consumption decreases by doing so.

    Which SAADC driver are you using, for the record?

    It may be helpful for you to see this low power SAADC example for reference. This example does not use PPI, but still achieves a lower power draw through using the LFCLK.

    lvpeng said:
    Can I turn off the SAADC?

    I am not sure what you mean to ask here - are you asking if you can turn off the SAADC? If so, you may turn off the SAADC whenever it is not actively sampling (in this case, you will loose your sample). 

    Best regards,
    Karl

  • Hi Karl,

    Thank you very much!

    I change my clock source, use RTC to trigger the SAADV(PPI mode), the baseline current consumption is about 12uA. This is a good news!!

    Now, I have another problem.

    What is the low-power mode of SAADC?

    When I use RTC+SAADC (PPI mode), if enable low-power mode, baseline current is 12uA;  If I disable low-power mode, baseline current is 700uA, why?

    I mean:

    if (saadv_config.low_power_mode == true),   then current = 12uA;

    if (saadv_config.low_power_mode == false), then current = 700uA;

    why?

  • Hello,

    lvpeng said:
    I change my clock source, use RTC to trigger the SAADV(PPI mode), the baseline current consumption is about 12uA. This is a good news!!

    I am happy to hear that you were able to achieve the low power consumption, great! :)

    lvpeng said:
    What is the low-power mode of SAADC?

    The low power mode will turn off the SAADC between samplings. So, this is why you are seeing a sharp increase in power consumption when not using low-power mode.

    Best regards,
    Karl

Related