Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Read multiple ADC samples on single channel

Hi,

I'm trying to read the battery voltage of a custom board from the VDDHDIV5  channel. I'm using FreeRTOS in my project. I would like to read trigger the ADC to read 5 samples(non-blocking) once every hour. I tried the below pseudo code to trigger the read but I noticed that only one reading is present in the buffer.

nrf_saadc_value_t raw_value[5] = {0};

void saadc_handler(nrf_drv_saadc_evt_t const * p_event)
{
    if(p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        raw_val = *(p_event->data.done.p_buffer);
        test = (raw_val*10/1024);
        
        //Notify saadc_thread
    }

}

void saadc_init()
{
    uint32_t err_code;

    //SAADC peripheral configuration
    nrf_drv_saadc_config_t m_saadc_config = 
    {
        .interrupt_priority = APP_IRQ_PRIORITY_LOW,
        .low_power_mode = false,
        .oversample = NRF_SAADC_OVERSAMPLE_DISABLED,
        .resolution = NRF_SAADC_RESOLUTION_10BIT
    };

    // Channel configuration
    //Internal reference is 0.6V
    nrf_saadc_channel_config_t m_channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDDHDIV5);
    m_channel_config.acq_time = NRF_SAADC_ACQTIME_10US;
    m_channel_config.gain = NRF_SAADC_GAIN1_6;

    err_code = nrf_drv_saadc_init(&m_saadc_config, saadc_handler);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &m_channel_config);
    APP_ERROR_CHECK(err_code);
}

void saadc_sample()
{
    nrf_drv_saadc_buffer_convert(raw_value, 5);
    
    for(uint8_t i=0; i<5; ++i)
        nrf_drv_saadc_sample();
}

static void saadc_thread(void * arg)
{
    // Call saadc_sample and wait for a notification. And then delay for 1 hour
}


I tried two more things and noticed different output

  • The SAADC example in the SDK. The code was running fine and the ADC values were correct.
  • Call saadc_sample in the SAADC handler on NRF_DRV_SAADC_EVT_DONE. The ADC values were correct but this is not a desirable situation as I don't need the SAADC to constantly sample
  • Change the size of raw_value to 1. The ADC value was wrong. I tried this with and without oversampling.

MCU - nRF52833-QDAAA0

SDK - nRF5 SDK 17.1.0

With FreeRTOS

Parents
  • Gowtham,

    Thanks for waiting. Have you tried your application in the debugger mode? 

    It seems like there might be some race conditions in your application causing some deadlock somewhere in your application context. Maybe wrong priorities within other tasks. It is hard to say without knowing all the contexts running in your application. 

    If you do not find any race conditions or deadlocks in your application when you run this in the debug mode. Then please share your project so that I try to find the context which probably is starving other contexts.

  • Hi Susheel,

    I've attached 2 projects.

    1. blink_freertos-adc-test: Based on the blinky_freertos project. I've added a task to sample the SAADC VDDHDIV5 channel. The ADC value read is around 600 when the VDD value is around 4.06V

    2. saadc-pcb-test: Based on the saadc peripheral example. I've changed the channel to VDDHDIV5. The ADC value read is around 230 when the VDD value is around 4.06V.

    Both the projects are based on the nRF5 SDK v17.1.0 and were tested on the same PCB.

    I feel that this seems to be an issue with how the values are read rather than FreeRTOS. 

    blinky_freertos-adc-test.zip
    saadc-pcb-test.zip

  • Hi,

    It seems like you are measuring the correct raw value. Following the the macro from ble_app_proximity and multipling the ADC value by 5 I get 4042 mV. 

    #define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
            ((((ADC_VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_PRE_SCALING_COMPENSATION)

    Calculation

    ((230*5) * 600)/1024 * 6 = 4042 

    Best regards,

    Vidar

  • Hi Vidar,

    I am getting the correct raw value only on the saadc-test-pcb project which is based on the SAADC example. When I program the blink_freertos-adc-test project with the same setup, I'm getting an incorrect raw value of 600. A raw value of 600 translates to ~10.5V, which is wrong.

    Thanks,

    Gowtham

  • Hi Gowtham,

    Strangely I get the same measurement results with both saadc-test-pcb and blinky_freertos when testing this on a nRF52833 DK here. The measured value was ~291 when VVDH=5.084V.

    Please confirm if the MAINREGSTATUS register is set to high as shown below.

    Best regards,

    Vidar

  • Hi Vidar,

    I checked the value of MAINREGSTATUS and it is High when I tried both the projects.

    Additionally, please don't check the value using a breakpoint and instead use the Watch window as I've noticed that I get the correct value sometimes when the code execution stops. And usually the first or second time it hits the breakpoint, it reads the correct value.

    Thanks,

    Gowtham

  • Hi Gowtham,

    Thanks for confirming. The problem is that I am consistently measuring 291 here with minor deviation, both with breakpoints and watchpoints. Also don't see why this should have made any difference. 

    Have you tried to see if it behaves differently with different build configurations (i.e. Debug vs Release) and would you mind recording a short screencast of when you are monitoring the sample buffer?

    Best regards,

    Vidar

Reply
  • Hi Gowtham,

    Thanks for confirming. The problem is that I am consistently measuring 291 here with minor deviation, both with breakpoints and watchpoints. Also don't see why this should have made any difference. 

    Have you tried to see if it behaves differently with different build configurations (i.e. Debug vs Release) and would you mind recording a short screencast of when you are monitoring the sample buffer?

    Best regards,

    Vidar

Children
  • Hey Vidar,

    Sorry for the delay in replying. I was able to make a recording of this issue. The battery voltage at the time of recording was around 3.97V.  You can notice that the first sample had a value close to the expected value while the next sample onwards it's completely wrong.

  • Hi,

    Do you see the same if you comment the 'raw_value = *(p_event->data.done.p_buffer);' line in your saadc_handler() callback, and does it make any difference if you use the 'Debug' build configuration instead of 'Release'?

  • Hi Vidar,

    I've tried commenting the line you have mentioned and I'm still facing the same issue. I tried the Debug variant and the issue is still seen.

  • Hi Gowtham,

    What I noticed from the video recording you made is that the false readings appear to be left-shifted by 1 (i.e. multiplied by 2), which isn't something I have seen before. I also noticed that you made some changes to the code compared to what you sent me.

  • Hi Vidar,

    I think I made some changes in that project after I had uploaded the project zip here. I downloaded the same zip file I had uploaded and tested it. I can still observe the same issue.

    Can you help me with understanding the difference in the method of using the SAADC between the 2 projects I had uploaded since the saadc-pcb-test.zip project gives the correct values.

    Is this something to do with the usage of tasks?

    I'm ruling out a hardware issue since I'm getting proper values from the saadc-pcb-test project

Related