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

SAADC with

I need to measure with SAADC two channels in the same time (NRF_SAADC_INPUT_AIN6 and NRF_SAADC_INPUT_AIN4).

Is possible ?

Have you an code example?

Thanks

Marco

Parents
  • Dear, all.

    I have activated the second channel:

    #define NRFX_SAADC_PULSE_CHANNEL_CONFIG_SE(PIN_P) \
    {                                                   \
        .resistor_p = NRF_SAADC_RESISTOR_DISABLED,      \
        .resistor_n = NRF_SAADC_RESISTOR_DISABLED,      \
        .gain       = NRF_SAADC_GAIN1_6,                \
        .reference  = NRF_SAADC_REFERENCE_INTERNAL,     \
        .acq_time   = NRF_SAADC_ACQTIME_3US,           \
        .mode       = NRF_SAADC_MODE_SINGLE_ENDED,      \
        .burst      = NRF_SAADC_BURST_DISABLED,         \
        .pin_p      = (nrf_saadc_input_t)(PIN_P),       \
        .pin_n      = NRF_SAADC_INPUT_DISABLED          \
    }
    
    
    #define NRFX_SAADC_INEX_CHANNEL_CONFIG_SE(PIN_P) \
    {                                                   \
        .resistor_p = NRF_SAADC_RESISTOR_DISABLED,      \
        .resistor_n = NRF_SAADC_RESISTOR_DISABLED,      \
        .gain       = NRF_SAADC_GAIN1_6,                \
        .reference  = NRF_SAADC_REFERENCE_INTERNAL,     \
        .acq_time   = NRF_SAADC_ACQTIME_3US,           \
        .mode       = NRF_SAADC_MODE_SINGLE_ENDED,      \
        .burst      = NRF_SAADC_BURST_DISABLED,         \
        .pin_p      = (nrf_saadc_input_t)(PIN_P),       \
        .pin_n      = NRF_SAADC_INPUT_DISABLED          \
    }
    
    nrf_saadc_channel_config_t channel_config_INEX  = NRFX_SAADC_INEX_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);
    nrf_saadc_channel_config_t channel_config_PULSE = NRFX_SAADC_PULSE_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
    
    
    
    void saadc_init(unsigned char type)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_saadc_init(NULL, saadc_PULSE_INEX_callback);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_channel_init(0, &channel_config_INEX);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(1, &channel_config_PULSE);
        APP_ERROR_CHECK(err_code);
        
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool_scann[0], SAMPLES_IN_BUFFER_SCANN);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool_scann[1], SAMPLES_IN_BUFFER_SCANN);
        APP_ERROR_CHECK(err_code);
    }
    
    

    seem work but sametime in the buffer I find the values exchanged between channels. WHY ?

    this is my callback function:

    void saadc_PULSE_INEX_callback(nrf_drv_saadc_evt_t const * p_event)
    {
      nrf_saadc_value_t adc_result;
      uint16_t value_mV_local;
      uint16_t value_mV_acc;
      int i;
     
        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_SCANN);
            APP_ERROR_CHECK(err_code);
                    
            adc_result = p_event->data.done.p_buffer[0];
            adc_value_inex = ADC_RESULT_IN_MILLI_VOLTS(adc_result);//+ DIODE_FWD_VOLT_DROP_MILLIVOLTS;
        
            adc_result = p_event->data.done.p_buffer[1];
            adc_value_pulse = ADC_RESULT_IN_MILLI_VOLTS(adc_result);//+ DIODE_FWD_VOLT_DROP_MILLIVOLTS;
       }
     }

    with this code I ask a start of new conversion

              nrf_drv_saadc_sample();
              while(!u_STATO10.STATO10_bit.mm_EOC);

    the bit mm_EOC is for waiting the end of conversion. This is set in the callback with the event DONE.

    Marco

  • I had forgotten to say:

    #define SAMPLES_IN_BUFFER_SCANN 2

    static nrf_saadc_value_t m_buffer_pool_scann[2][SAMPLES_IN_BUFFER_SCANN];

    Marco

  • No, is impossible for me now.

    static void lpcomp_event_handler(nrf_lpcomp_event_t event)
    {
      if (event == NRF_LPCOMP_EVENT_DOWN)
      {
          nrf_gpio_pin_set(PIN_P0_20_TP6);
              
          u_STATO10.STATO10_bit.mm_EOC = 0;
          nrf_drv_saadc_sample();
          while(!u_STATO10.STATO10_bit.mm_EOC);
    
          buff_I[puntIP]=adc_value_inex;
          buff_P[puntIP]=adc_value_pulse;
          puntIP++;
          if (puntIP>99)puntIP=0;
    
          nrf_gpio_pin_clear(PIN_P0_20_TP6);
    
        }
    }
    

    I working on my target and I don' start a conversion with a timer but when a pulse arrive on AIN5.

    I trigger this event with a LPCOMP event DOWN on AIN5.

    I have tested it with the PO_20 test point and this event is perfectly synchronized with the AIN5.

    I have discovered that if the time between 2 conversion is more then 10 mS the error do not appear

    Report--00038.pdf

    I have send you my situation.

    In the report the signal RED is connected to AIN5 in order to generate an event on LPCOMP

    In BLU one of the 2 signal that I need to measure with the SAADC

    In yellow the signal PO_20 (test point) this signal go up when the evend LPCOMP down arrive and go down after the conversion (see my code above).

    In the buffer buff_I and buff_P I store my conversion and sometime I read a zero value instead the correct value. see file in attach.

    Note that on the oscilloscope the signal BLU is always UP when the YELLOW signal arrive.

  • I had forgotten to say that the correct value (thai is 0 in this buffer) is located with same offset in the other buffer (of the other signal)

  • I have discovered now that when the data from ADC is swapped, this situation continues until I reset the system.

    In previus immage I stopped the debug at the first 0. The other values after the 0 are old values on the buffer

  • ok. so the issue is that the adc is not triggered on every fall on the input pulse, is that maybe the case?

    The issue may be that you don't have time for all interrupts. Either, they are too fast on it's own, or there is a possibility that you don't get the lpcomp interrupts (lpcomp_event_handler) in time, because the CPU is busy doing something else, such as handling one of the ADC events. 

    I suggest that you try to use PPI, like it is done in the example. It sets up a timer, and then uses the ppi to trigger the sampling on this event, rather than handling the timer interrupt using the CPU.

  • Dear Edvin,

    the interrup is triggered on all fall edge. The LPCOM work perfectly and follow all edge.

    The ADC in scann mod, on 2 channels, work but some times the data are swapped into the doubble buffer.

    I have found other with my problem, see: https://devzone.nordicsemi.com/f/nordic-q-a/16885/saadc-scan-mode-sample-order-is-not-always-consistent

    For now I have resolved using two call, each with only one channel ON.

        err_code = nrf_drv_saadc_channel_init(0, &channel_config_PULSE);
        APP_ERROR_CHECK(err_code);
        nrfx_saadc_sample_convert(0, &value_1);
        adc_value_pulse = ADC_RESULT_IN_MILLI_VOLTS(value_1);      //
        if (adc_value_pulse>35000) adc_value_pulse=0;
        err_code = nrf_drv_saadc_channel_uninit(0);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_channel_init(0, &channel_config_INEX);
        APP_ERROR_CHECK(err_code);
        nrfx_saadc_sample_convert(0, &value_2);
        adc_value_inex = ADC_RESULT_IN_MILLI_VOLTS(value_2);      //
        if (adc_value_inex>35000) adc_value_inex=0;
        err_code = nrf_drv_saadc_channel_uninit(0);
        APP_ERROR_CHECK(err_code);
    

    In this configuration all work good, also using 1 mS between two fall edge.

    the above code use 55uS for both channels.

    But this is not the correct solution. I hope to found the error in the scann mode configurations

    Thanks

    Marco

Reply
  • Dear Edvin,

    the interrup is triggered on all fall edge. The LPCOM work perfectly and follow all edge.

    The ADC in scann mod, on 2 channels, work but some times the data are swapped into the doubble buffer.

    I have found other with my problem, see: https://devzone.nordicsemi.com/f/nordic-q-a/16885/saadc-scan-mode-sample-order-is-not-always-consistent

    For now I have resolved using two call, each with only one channel ON.

        err_code = nrf_drv_saadc_channel_init(0, &channel_config_PULSE);
        APP_ERROR_CHECK(err_code);
        nrfx_saadc_sample_convert(0, &value_1);
        adc_value_pulse = ADC_RESULT_IN_MILLI_VOLTS(value_1);      //
        if (adc_value_pulse>35000) adc_value_pulse=0;
        err_code = nrf_drv_saadc_channel_uninit(0);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_channel_init(0, &channel_config_INEX);
        APP_ERROR_CHECK(err_code);
        nrfx_saadc_sample_convert(0, &value_2);
        adc_value_inex = ADC_RESULT_IN_MILLI_VOLTS(value_2);      //
        if (adc_value_inex>35000) adc_value_inex=0;
        err_code = nrf_drv_saadc_channel_uninit(0);
        APP_ERROR_CHECK(err_code);
    

    In this configuration all work good, also using 1 mS between two fall edge.

    the above code use 55uS for both channels.

    But this is not the correct solution. I hope to found the error in the scann mode configurations

    Thanks

    Marco

Children
  • Hello,

    Sorry. I forgot to mention that if you have two channels that are enabled, the scan function will scan both channels. I wasn't aware that you wanted to scan on different times based on two different input pulses.

    The ticket that you link to is not entirely the same. We have seen similar cases when they use the internal SAADC timer to trigger samples, when they are sampling very fast, and have several channels.

    If you want to measure on different times, you need to disable one channel at the time, like you do here.

    How does that behave? I am still a bit confused about your description.

     

    Marco Pennacchietti said:
    I had forgotten to say that the correct value (thai is 0 in this buffer) is located with same offset in the other buffer (of the other signal)

     So how is your channels mixed up? Could you clarify?

    Best regards,

    Edvin

  • maybe I can't explain myself well.

    The event of LPCOM is only on 1 signal.

    When this event start I need to scan both signals in the same time.

    In the buffer:  static nrf_saadc_value_t m_buffer_pool_scann[2][2];

    Normally I found in position 0 the first signal and in position 1 the second signal. And this is OK, all seem to work good.

    Sometimes during the acquisition of the signals I find the values exchanged, so in position 0 the second signal and in position 1 the first signal. This situation continues and then every once in a while it is reversed.

    I don't understand. Other people on the web complain about this problem

    Marco

  • Hello Marco,

    Ok. I think I understand. Does this happen when you disable and enable the different channels? I am sorry to ask the same questions over and over, but I try to think of why this may happen. I still don't think it is exactly the same as in the ticket that you link to, and I hope that it isn't, because there is really no good solution to that issue.

    So the reason why you disable and enable the channels is that you want to measure on different times, is that correct? Or do you intend to measure them at the same time?

    Because when you have two ADC channels, and you trigger the scan, it will scan both channels one after the other (because there is only one physical ADC on the chip).

    What I suspect is happening is that you are triggering the scan via CPU interrupts, the interrupts are too fast for the CPU to handle all, so some of them are skipped. What I suggest is that you try to use the PPI to trigger the interrupts, which is more efficient, and you may not miss any of the events.

    Now, the reason that the positions swap is that the buffer isn't aware of how many channels, or which channel the interrupts are coming from. This is not a problem if you only use one channel, but it is if you have more. If one sample is interrupted, it may happen that it scans twice on one channel, and then they will be swapped. 

    So: Do you disable/enable the channels? And have you tried triggering them via PPI? And do you need to measure at different points in time, or can you measure both channels at the same time?

  • Thank Edvin ! Difficult to find help in mid-August

    Yes I need to measure both channels at the same time (AIN4 and AIN6)

    If I enable only one channel all is perfect, if I anable 2 channel sometimes I have the swap.

    I completely agree with you that the problem is that the micro is too busy (Soft device enabled, the micro send the data via BT, LPCOMP enabled, ADC enabled).
    I dont use PPI.  Into the LPCMP event I ask one conversion and wait the evet done. SO I ask, in one LPCOMP event, one value from AIN4 and one value from AIN6 (in the same time).
    The maximum frequency of LPCOMP event is 800 uS (0,8 mS).
    But the problem appear also at low frequency (20 mS).
    For now I heve resolve the problem with 2 single conversion with about 20 uS of delay between the two conversions.
    Thank very mutch for your help
    Marco
Related