<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>nRF9160 SAADC nrfx api: high power consumption after uninit</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/92393/nrf9160-saadc-nrfx-api-high-power-consumption-after-uninit</link><description>Hi, 
 as mentioned in a previous ticket I&amp;#39;m developing a successor to one of our products. One important feature is that we can change pin functions anytime. (output, input, pwm, ain, ...) Because of this the devicetree isn&amp;#39;t the way to go for us and</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Thu, 29 Sep 2022 14:01:27 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/92393/nrf9160-saadc-nrfx-api-high-power-consumption-after-uninit" /><item><title>RE: nRF9160 SAADC nrfx api: high power consumption after uninit</title><link>https://devzone.nordicsemi.com/thread/388598?ContentTypeID=1</link><pubDate>Thu, 29 Sep 2022 14:01:27 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:fed2e421-013b-4385-a0c7-cc82164f4512</guid><dc:creator>H&amp;#229;kon Alseth</dc:creator><description>&lt;p&gt;Hi Johannes,&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Thank you for updating with your findings!&lt;/p&gt;
[quote user="Johannes"]&lt;p&gt;&lt;span&gt;what a timing. I just wanted to post my findings. ^^&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;What I found is that in the zephyr implementation after a blocking adc measurement is triggered the adc is stopped with exactly this call.&lt;br /&gt;When issuing a stop task after the measurement has finished the power consumption is down to what I was expecting.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Another thing that needs to be done is to add the&amp;nbsp;&lt;/span&gt;saadc_channels_disable function to the SDK version 1.8.0. Without it the pin cannot be used for anything else.&lt;/p&gt;[/quote]
&lt;p&gt;Yes, this is similar to the fix that we added ~6 months ago:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/zephyrproject-rtos/hal_nordic/blob/master/nrfx/drivers/src/nrfx_saadc.c#L295"&gt;https://github.com/zephyrproject-rtos/hal_nordic/blob/master/nrfx/drivers/src/nrfx_saadc.c#L295&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Kind regards,&lt;/p&gt;
&lt;p&gt;Håkon&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: nRF9160 SAADC nrfx api: high power consumption after uninit</title><link>https://devzone.nordicsemi.com/thread/388395?ContentTypeID=1</link><pubDate>Wed, 28 Sep 2022 14:12:00 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:482f9f21-a7e6-4783-b2eb-f805168476b3</guid><dc:creator>JoEi</dc:creator><description>&lt;p&gt;Hi&amp;nbsp;&lt;span&gt;H&amp;aring;kon,&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;what a timing. I just wanted to post my findings. ^^&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;What I found is that in the zephyr implementation after a blocking adc measurement is triggered the adc is stopped with exactly this call.&lt;br /&gt;When issuing a stop task after the measurement has finished the power consumption is down to what I was expecting.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Another thing that needs to be done is to add the&amp;nbsp;&lt;/span&gt;saadc_channels_disable function to the SDK version 1.8.0. Without it the pin cannot be used for anything else.&lt;/p&gt;
&lt;p&gt;Here are the functions with my changes:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;nrfx_err_t nrfx_saadc_mode_trigger(void)
{
    NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_UNINITIALIZED);
    NRFX_ASSERT(m_cb.saadc_state != NRF_SAADC_STATE_IDLE);

    if (!m_cb.p_buffer_primary)
    {
        return NRFX_ERROR_NO_MEM;
    }

    nrfx_err_t result = NRFX_SUCCESS;
    switch (m_cb.saadc_state)
    {
        case NRF_SAADC_STATE_SIMPLE_MODE:
            nrf_saadc_enable(NRF_SAADC);
            // When in simple blocking or non-blocking mode, buffer size is equal to activated channel count.
            // Single SAMPLE task is enough to obtain one sample on each activated channel.
            // This will result in buffer being filled with samples and therefore END event will appear.
            nrf_saadc_buffer_init(NRF_SAADC, m_cb.p_buffer_primary, m_cb.size_primary);
            if (m_cb.event_handler)
            {
                m_cb.saadc_state = NRF_SAADC_STATE_SIMPLE_MODE_SAMPLE;
                nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START);
            }
            else
            {
                nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START);
                while (!nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_STARTED))
                {}
                nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_STARTED);

                nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_SAMPLE);
                while (!nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_END))
                {}
                nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END);
                nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_STOP);
                nrf_saadc_disable(NRF_SAADC);
            }
            break;

        case NRF_SAADC_STATE_ADV_MODE:
            nrf_saadc_enable(NRF_SAADC);
            if (m_cb.event_handler)
            {
                // When in advanced non-blocking mode, latch whole buffer in EasyDMA.
                // END event will arrive when whole buffer is filled with samples.
                m_cb.saadc_state = NRF_SAADC_STATE_ADV_MODE_SAMPLE;
                nrf_saadc_buffer_init(NRF_SAADC, m_cb.p_buffer_primary, m_cb.size_primary);
                nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START);
                break;
            }

            // When in advanced blocking mode, latch single chunk of buffer in EasyDMA.
            // Each chunk consists of single sample from each activated channels.
            // END event will arrive when single chunk is filled with samples.
            nrf_saadc_buffer_init(NRF_SAADC,
                                  &amp;amp;m_cb.p_buffer_primary[m_cb.samples_converted],
                                  m_cb.channels_activated_count);

            nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START);
            while (!nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_STARTED))
            {}
            nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_STARTED);

            if (m_cb.oversampling_without_burst)
            {
                // Oversampling without burst is possible only on single channel.
                // In this configuration more than one SAMPLE task is needed to obtain single sample.
                uint32_t samples_to_take =
                    nrf_saadc_oversample_sample_count_get(nrf_saadc_oversample_get(NRF_SAADC));

                for (uint32_t sample_idx = 0; sample_idx &amp;lt; samples_to_take; sample_idx++)
                {
                    nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_DONE);
                    nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_SAMPLE);
                    while (!nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_DONE))
                    {}
                }
            }
            else
            {
                // Single SAMPLE task is enough to obtain one sample on each activated channel.
                // This will result in chunk being filled with samples and therefore END event will appear.
                nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_SAMPLE);
            }
            while (!nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_END))
            {}
            nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END);
            nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_STOP);

            m_cb.samples_converted += m_cb.channels_activated_count;
            if (m_cb.samples_converted &amp;lt; m_cb.size_primary)
            {
                result = NRFX_ERROR_BUSY;
            }
            else
            {
                m_cb.samples_converted  = 0;
                m_cb.p_buffer_primary   = m_cb.p_buffer_secondary;
                m_cb.size_primary       = m_cb.size_secondary;
                m_cb.p_buffer_secondary = NULL;
            }
            nrf_saadc_disable(NRF_SAADC);
            break;

        default:
            result = NRFX_ERROR_INVALID_STATE;
            break;
    }

    return result;
}
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;static void saadc_channels_disable(uint32_t channel_mask)
{
    while (channel_mask)
    {
        uint8_t channel = __CLZ(__RBIT(channel_mask));
        channel_mask &amp;amp;= ~(1 &amp;lt;&amp;lt; channel);
        m_cb.channels_configured &amp;amp;= ~(1 &amp;lt;&amp;lt; channel);
        m_cb.channels_activated &amp;amp;= ~(1 &amp;lt;&amp;lt; channel);

        m_cb.channels_pselp[channel] = NRF_SAADC_INPUT_DISABLED;
        m_cb.channels_pseln[channel] = NRF_SAADC_INPUT_DISABLED;
        nrf_saadc_channel_input_set(NRF_SAADC, channel,
                                    NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED);
    }
    m_cb.channels_activated_count = 0;
    for(int i = 0; i &amp;lt; SAADC_CH_NUM; i++)
    {
        if(m_cb.channels_activated &amp;amp; (1 &amp;lt;&amp;lt; i))
        {
            m_cb.channels_activated_count++;
        }
    }
}

void nrfx_saadc_uninit(void)
{
    nrfx_saadc_abort();
    NRFX_IRQ_DISABLE(SAADC_IRQn);
    nrf_saadc_disable(NRF_SAADC);
    saadc_channels_disable(m_cb.channels_configured | m_cb.channels_activated);
    m_cb.saadc_state = NRF_SAADC_STATE_UNINITIALIZED;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Kind regards,&lt;br /&gt;Johannes&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: nRF9160 SAADC nrfx api: high power consumption after uninit</title><link>https://devzone.nordicsemi.com/thread/388376?ContentTypeID=1</link><pubDate>Wed, 28 Sep 2022 13:38:54 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:6893c1f2-a9c3-456b-a667-e99cfc5363c3</guid><dc:creator>H&amp;#229;kon Alseth</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Could you try issuing a _STOP task before uninit()?&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_STOP);&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Kind regards,&lt;/p&gt;
&lt;p&gt;Håkon&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>