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

Calibrating SAADC on nrf52832

Hi,

I am using an nRF52832 with S132 and SDK v15.0.0 and already read in the forum about issues related to the SAADC calibration (inlcuing the erratum  [86]). The problem I have is that the ADC constantly (not only once!) delivers wrong data after I call the calibrate_offset function.

The stuff that happens over time is basically:

-> The SAADC is initialised

-> the channels (2) are initialised

-> the buffer_convert function is called

-> (because the buffer-convert funtion was already called and the SAADC is in IDLE although no START or SAMPLE task was triggered yet) -> the nrfx_saadc_abort() function is called

This is the first point, where somthing goes wrong since sometimes the nrfx_saadc_abort() itself hangs when waiting for the SAADC to become IDLE again. Do I have to do a dummy TASK_SAMPLE before calling the abort function so that a conversion is in progress? it seems that simply aborting without issuing a SAMPLE before fails in waiting for "NRFX_WAIT_FOR((m_cb.adc_state != NRF_SAADC_STATE_IDLE), HW_TIMEOUT, 0, result);". (But I have to call the abort function to get into IDLE after calling buffer_convert?)

->  nrfx_saadc_calibrate_offset() is called

-> The values i get from this time by calling TASK_SAMPLE  are wrong

Besides of the concrete problem, I have the following questions, wo which I did not yet find an answer to.

1.) I am NOT using SAADC in LP Mode. Is the workaround for the erratum [86] still necessary for SDK V15.0.0 or is ia patch alredy somehow included in v15?

2.) I am unsure about how to implement the workaround. It is described as Stopping the SAADC after calibration, but stopping seems to invole waiting for an STOPPED EVENT. Do i have to wait and therefore somehow poll for that event? What is an easy way to do that?

3.) In all the SAADC examples, I see that the event handler checks for the NRFX_SAADC_EVT_DONE event and gets the data from the buffer. Why is that done, when there is explicitly stated that this event does not guaratee that the samples are already in RAM? Why not waiting for the END event? The p_buffer->type does not even seem to expose the END event? Why is that?

4.) I see that in examples, in the Event handler the occurence of the event CALIBRATEDONE is used to again call buffer_convert to set up the buffer again. If i call the calibrate_offset function before a call to buffer_convert, i guess thats a problem because in the event handler the buffer is set to the last one used, but there is no (useful) "last" buffer in this case?)

5.) Could someone provide a minimal working example (minimal main program plus callback) for just initialising the ADC / the ADC channels, perform calibration and set up the buffer for a "real" conversion directly after a startup? All the examples I found use cyclic turning on/off or inti / uninits that make things a bit unclear for a basic understanding.

Thanks a lot!

Parents
  • Hi Kenneth,

    Thanks for the reply.

    According to the numbering of my initial questions:

    3.) Good to know, so it is no problem with IR processing because the delay until the IR is handled, is big enough in any case?

    4.) Will have to check where in the forum I saw it, I will come back to that.

    5.) Well there is one thing I want to ask about this example which is also somthing I did not understand in another example: How is the call to err_code = nrf_drv_saadc_init(NULL, saadc_callback); supposed to work?

    I use nrfx_saadc_init(NULL,saadc_callback); according to the new API in SDK V15, but there is a line in the function "nrfx_saadc_init(NULL,saadc_callback);" that obviously returns immediately if the function is called with a NULL pointer. What is the reason for nto initialising with a proper "ADC config structure" ?

    Thanks

  • About 5) What file and line number are you referring to?

    Kenneth

  • E.g. line number 99 in the code example you shared above.

  • It is example code so please change this as you see fit, but basically using NULL will set default settings from sdk_config.h

    __STATIC_INLINE ret_code_t nrf_drv_saadc_init(nrf_drv_saadc_config_t const * p_config,
                                                  nrf_drv_saadc_event_handler_t  event_handler)
    {
        if (p_config == NULL)
        {
            static const nrfx_saadc_config_t default_config = NRFX_SAADC_DEFAULT_CONFIG;
            p_config = &default_config;
        }
        return nrfx_saadc_init(p_config, event_handler);
    }

  • Hi Kenneth,

    Well sorry, I could have found out that for myself. My program crashed around the line, where the ADC is initilaised with "NULL", so I was a bit blinded but actually, the crash happened somwhere else.

    However, back to the main topic of my question: I still have troubles using the offset calibration. My program does essentially the same as your provided example code and more specifically, it uses the exact code of the "calibrate_saadc" function.

    Unfortunately, when i have the call to the calibrate function in my code (right after nrfx_saadc_init), the program hangs in "nrfx_saadc_sample()" with "NRFX_ERROR_INVALID_STATE" after the first adc conversion (1 sample per CH) is complete.

    This does not happen when I comment the line with the call to the calibrate function during adc initialisation.

    Any hints?

  • Hi Kenneth,

    It´s been some time. any update to this?

  • I am not sure what more debugging that can be done from here, but looking at the code it seems that nrfx_saadc_sample() will report NRFX_ERROR_INVALID_STATE if m_cb.adc_state != NRF_SAADC_STATE_BUSY.

    So maybe your first task is to set a breakpoint when err_code = NRFX_ERROR_INVALID_STATE; in nrfx_saadc_sample() to find the actual value of m_cb.adc_state. And then you can add a log output every time m_cb.adc_state is set to the specific value to find which function is called that set it to !NRF_SAADC_STATE_BUSY in this case.

    Best regards,
    Kenneth

Reply
  • I am not sure what more debugging that can be done from here, but looking at the code it seems that nrfx_saadc_sample() will report NRFX_ERROR_INVALID_STATE if m_cb.adc_state != NRF_SAADC_STATE_BUSY.

    So maybe your first task is to set a breakpoint when err_code = NRFX_ERROR_INVALID_STATE; in nrfx_saadc_sample() to find the actual value of m_cb.adc_state. And then you can add a log output every time m_cb.adc_state is set to the specific value to find which function is called that set it to !NRF_SAADC_STATE_BUSY in this case.

    Best regards,
    Kenneth

Children
Related