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 try it today, but there r no effect.  

    the error is same with that before.

    how can u do ?

  • nrf_drv_saadc_uninit() function code has some bugs as below:

    nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);

    Wait for ADC being stopped.
    uint32_t timeout = HW_TIMEOUT;
    while (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED) == 0 && timeout > 0)
    {
      --timeout;
     }

    while (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED) == 0 && timeout > 0)
    {
      --timeout;
     }

    the code cant check the stop interrput ,as init some bugs in next init code.

  • What do you mean by this: "the code cant check the stop interrput ,as init some bugs in next init code"? Are you actually checking the error codes from your calls to nrf_drv_saadc_*, or are they only assigned? You say you get error 0x08 when calling nrf_drv_saadc_sample, this indicate that the driver is in IDLE state, normally because no buffer have been setup. You should have received an error code when you called one of the nrf_drv_saadc_* functions.

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

Reply
  • 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);
                }
            }
        }
    }

Children
Related