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

The Saadc of issue of uninit

i init the saadc and uinit saadc ,then init saadc again. my code is below:

err_code = nrf_drv_saadc_init(NULL, saadc_callback);
err_code = nrf_drv_saadc_channel_init(0, &channel_config_se1);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool, 1);

 nrf_drv_saadc_uninit();

err_code = nrf_drv_saadc_init(NULL, saadc_callback);
err_code = nrf_drv_saadc_channel_init(0, &channel_config_se1);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool, 1);

from now .the err_code is correct .

But when i use nrf_drv_saadc_sample(), geting a error in SAADC_IRQHandler. And this is my callback:

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
nrf_drv_saadc_buffer_convert(m_buffer_pool,1);
}

In SAADC_IRQHandler, the code enter in below:

if (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED))
{
nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED);
NRF_LOG_DEBUG("Event: %s.\r\n", (uint32_t)EVT_TO_STR(NRF_SAADC_EVENT_STOPPED));
m_cb.adc_state = NRF_SAADC_STATE_IDLE;
}

if i dont use  nrf_drv_saadc_uninit(),there is greater.

what i can do???

Parents
  • Hello, can you explain what are you trying to achieve? What is your setup MCU, sdk, softdevice? what does the error says? Recently I had problems while using SAADC. I would recommend you to take a look at proximity example. Moreover, do you do temperature calibration?

  • i use the softdevice, sdk is nRF5_SDK_12.3.0_d7731ad.

    my error is that i said in above. 

    when i use saadc,anything is ok. But i wanna uninit the saadc to power down the consumption.

    But when i init saadc in twice more,saadc cant work well. 

     nrf_drv_saadc_sample error is 0x08, That means saadc is not busy.

    i bubeg the code , and i find the code enter if (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED)) in SAADC_IRQHandler.

    why when i init saadc in twice more,the code enter nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED)???

  • I guess the problem is inside the SAADC_IRQHandler. When using the uninit inside the callback there is a NRF_SAADC_EVENT_STOPPED event created. As the handling of the end event in line 117 (nRF5_SDK_12.3.0_d7731ad) is not terminating the IRQ function, the stop event is handled in line 190, setting the state of the driver to NRF_SAADC_STATE_IDLE after the reinit has been performed in the callback. The next call to nrf_drv_saadc_sample is then creating the invalid state error.

    Solution: In SAADC_IRQHandler use else if to handle each kind of event:

    void SAADC_IRQHandler(void)
    {
        if (nrf_saadc_event_check(NRF_SAADC_EVENT_END))
        {
            nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
            NRF_LOG_DEBUG("Event: %s.\r\n", (uint32_t)EVT_TO_STR(NRF_SAADC_EVENT_END));
    
            if (!m_cb.low_power_mode || m_cb.conversions_end)
            {
                nrf_drv_saadc_evt_t evt;
                evt.type               = NRF_DRV_SAADC_EVT_DONE;
                evt.data.done.p_buffer = (nrf_saadc_value_t *)m_cb.p_buffer;
                evt.data.done.size     = m_cb.buffer_size;
    
                if (m_cb.p_secondary_buffer == NULL)
                {
                    m_cb.adc_state = NRF_SAADC_STATE_IDLE;
                }
                else
                {
                    m_cb.buffer_size_left   = m_cb.secondary_buffer_size;
                    m_cb.p_buffer           = m_cb.p_secondary_buffer;
                    m_cb.buffer_size        = m_cb.secondary_buffer_size;
                    m_cb.p_secondary_buffer = NULL;
                    if (!m_cb.low_power_mode)
                    {
                        nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
                    }
                }
                m_cb.event_handler(&evt);
                m_cb.conversions_end = false;
            }
        }
        else if (m_cb.low_power_mode && nrf_saadc_event_check(NRF_SAADC_EVENT_STARTED))
        {
            nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
            NRF_LOG_DEBUG("Event: %s.\r\n", (uint32_t)EVT_TO_STR(NRF_SAADC_EVENT_STARTED));
    
            if (m_cb.buffer_size_left > m_cb.active_channels)
            {
                // More samples to convert than for single event.
                m_cb.buffer_size_left -= m_cb.active_channels;
                nrf_saadc_buffer_init((nrf_saadc_value_t *)&m_cb.p_buffer[m_cb.buffer_size -
                                                                          m_cb.buffer_size_left],
                                      m_cb.active_channels);
            }
            else if ((m_cb.buffer_size_left == m_cb.active_channels) &&
    
                     (m_cb.p_secondary_buffer != NULL))
            {
                // Samples to convert for one event, prepare next buffer.
                m_cb.conversions_end  = true;
                m_cb.buffer_size_left = 0;
                nrf_saadc_buffer_init((nrf_saadc_value_t *)m_cb.p_secondary_buffer,
                                      m_cb.active_channels);
            }
            else if (m_cb.buffer_size_left == m_cb.active_channels)
            {
                // Samples to convert for one event, but no second buffer.
                m_cb.conversions_end  = true;
                m_cb.buffer_size_left = 0;
            }
            nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
            nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);
        }
        else if (nrf_saadc_event_check(NRF_SAADC_EVENT_CALIBRATEDONE))
        {
            nrf_saadc_event_clear(NRF_SAADC_EVENT_CALIBRATEDONE);
            NRF_LOG_DEBUG("Event: %s.\r\n", (uint32_t)EVT_TO_STR(NRF_SAADC_EVENT_CALIBRATEDONE));
            m_cb.adc_state = NRF_SAADC_STATE_IDLE;
    
            nrf_drv_saadc_evt_t evt;
            evt.type = NRF_DRV_SAADC_EVT_CALIBRATEDONE;
            m_cb.event_handler(&evt);
        }
        else if (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED))
        {
            nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED);
            NRF_LOG_DEBUG("SAADC IRQ -- Event: %s.\r\n", (uint32_t)EVT_TO_STR(NRF_SAADC_EVENT_STOPPED));
            m_cb.adc_state = NRF_SAADC_STATE_IDLE;
        }
        else
        {
            uint32_t          limit_flags = m_cb.limits_enabled_flags;
            uint32_t          flag_idx;
            nrf_saadc_event_t event;
    
            while (limit_flags)
            {
                flag_idx     = __CLZ(limit_flags);
                limit_flags &= ~((1UL << 31) >> flag_idx);
                event        = FLAG_IDX_TO_EVENT(flag_idx);
                if (nrf_saadc_event_check(event))
                {
                    nrf_saadc_event_clear(event);
                    nrf_drv_saadc_evt_t evt;
                    evt.type                  = NRF_DRV_SAADC_EVT_LIMIT;
                    evt.data.limit.channel    = LIMIT_EVENT_TO_CHANNEL(event);
                    evt.data.limit.limit_type = LIMIT_EVENT_TO_LIMIT_TYPE(event);
                    NRF_LOG_DEBUG("Event limit, channel: %d, limit type: %s.\r\n", evt.data.limit.channel, (uint32_t)EVT_TO_STR(evt.data.limit.limit_type));
                    m_cb.event_handler(&evt);
                }
            }
        }
    }

  • has this issue resolved in SDK 14 or SDK 15?

    Please reply.

  • I am facing the same issue as discussed above. I tried using else if case as suggested above and it solved the problem but I don't want to change the driver and would rather prefer use latest version of SDK if the problem is solved. I am using currently SDK 12. Kindly let me know if there is a SDK version which solves this issue.

  • I do not understand why this issue should apprear. The uninit function disable all interrupts before triggering STOP task. Implementing the workaround proposed by will most likely break the functionality of the abort function (see this thread for more details - this issue have been fixed in SDK 15).

  • hi:

    Long time no see.

    nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP) is triggered in uninit function,as the interupt is disabled,so it cant happed.

    But the init function will enable the interupt in next time,the stop task will happed immediatly.

    in ADCIRQ some of state will hava some problem,as i said in above.

    i agree that   said.

Reply Children
  • The uninit function will stay in a while loop until the STOPPED event is generated. There is no need for interrupts to be enabled in order for events to be generated. If you frequently pull the STOPPED event register, you will read the event when it is generated. If a timeout should happen for some reason, before the STOPPED event is generated, this should be caught by the ASSERT (given that you have enabled ASSERTS by defining symbol DEBUG_NRF in the preprocessor symbols). You will not be able to call init function before the STOPPED event is generated, or you will be trapped in assert handler.

  • hi: 

    The uninit function will stay in a while loop until the STOPPED event is generated.

    There are just a while,it cant be guaranteed to trigger the STOPPED event.its not very strict and may be have some except. i agree with u said in later.

Related