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

SAADC Scan Mode mixes channel buffers whan fast.

Hi, i have a strange problem which happens when i use scan mode to get 3 separate channels on saadc.

For example when i use uint32_t ticks = nrf_drv_timer_us_to_ticks(&m_timer, 200); everytihing is ok but whan i use 50us buffers get mixed up?

Is this possible?

I use nrf52 with sdk 12.2.0

  • I have 3 sensors. 1. is the IR sensor, 2. the microphone and 3. the battery measurement. IR sensor gave me around 400 and reacted to my movement. The microphone was around 1500 and the battery around 2200. So I took 3 channel but used one SEGGER_RTT_printf with filter like these: if (i % 3 == 0) SEGGER_RTT_printf(0, "fill: %d: %d\n", i, p_event->data.done.p_buffer[i]);. Now. When i was measuring at the timer rate of 50us it was mixed (i got sometimes 2000, sometimes 1500, sometimes 400) but when i used 200us it NEVER got mixed up. So that was my conclusion.

  • Here is what i have now and works for me. Didnt have a crash yet.

    I have one saadc_sampling_event_init which has a timer in it. For each channel i have separate callback and saadc_init function.

    I have created a function

    void saadc_uninit(void)
    {
      nrf_drv_saadc_uninit();
    }
    

    which i call after the measurement.

    So for example one procedure may look like this.

    void saadc_battery_level_callback(nrf_drv_saadc_evt_t const * p_event)
    {
      if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
      {
        ret_code_t err_code;
        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER); APP_ERROR_CHECK(err_code);
        //SEGGER_RTT_printf(0, "buffa: %d\n", p_event->data.done.p_buffer[0]);
        battery_level_saadc_value = (uint16_t)caluclate_average_result(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
        set_data_ready(true);
      }
    }
    
    void battery_channel_enable()
    {
      saadc_battery_level_init();
      saadc_sampling_event_enable();
    }
    
    void battery_channel_disable()
    {
      saadc_sampling_event_disable();
      saadc_uninit();
    }
    
    static void wait_for_sample_data()
    {
      while(!is_data_ready())
      {
        nrf_delay_ms(1);
        __WFE();
        __SEV();
        __WFE();
        nrf_delay_ms(1);
      }
      set_data_ready(false);
    }
    
    
    uint16_t get_battery_saadc_sample()
    {
      battery_channel_enable();
      wait_for_sample_data();
      battery_channel_disable();
      return(battery_level_saadc_value);
    }
    

    What do you think about nrf_delay_ms(1);. If i remove them i never got the data_ready.

  • @schef:I don't understand why you need a timer here, I assume you only need one sample per channel ? The saadc example we used the timer just to show how this can be done automatically and periodically with the help of EasyDMA. I'm not sure you need that for your use case.

  • I use timer for microphone to measure noise. Which needs to be measured through period of 30s.

Related