This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Setting up SAADC questions

I'm trying to setup the SAADC, I do this as much as possible without examples, so I really understand what is going on.

Setting up:

  ret_code_t err_code;

  adc_config.resolution = NRF_SAADC_RESOLUTION_14BIT;
  adc_config.oversample = NRF_SAADC_OVERSAMPLE_8X;
  adc_config.interrupt_priority = 2;
  adc_config.low_power_mode = false;

  err_code = nrfx_saadc_init(&adc_config,event_handler);
  APP_ERROR_CHECK(err_code);

  //RESULT = [V(P) – V(N) ] * GAIN/REFERENCE * 2^(RESOLUTION - m)

  //try first alone ain2 = Vcell10
  adc_channel_config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;
  adc_channel_config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;
  //Input ADC ideally around 0.6V So gain of 0.6/3 = 0.2
  adc_channel_config.gain = SAADC_CH_CONFIG_GAIN_Gain1_5;
  adc_channel_config.reference = SAADC_CH_CONFIG_REFSEL_Internal;
  adc_channel_config.acq_time = NRF_SAADC_ACQTIME_15US;
  adc_channel_config.mode = NRF_SAADC_MODE_SINGLE_ENDED;
  adc_channel_config.burst = NRF_SAADC_BURST_ENABLED;
  adc_channel_config.pin_p = NRF_SAADC_INPUT_AIN2;
  adc_channel_config.pin_n = NRF_SAADC_INPUT_DISABLED; //Single ended

  err_code = nrfx_saadc_channel_init(2,&adc_channel_config);
  APP_ERROR_CHECK(err_code);

After this I try to start an ADC task but it fails. In the function for starting:

nrfx_err_t nrfx_saadc_sample()
{
    NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);

    nrfx_err_t err_code = NRFX_SUCCESS;
    if (m_cb.adc_state != NRF_SAADC_STATE_BUSY)
    {
        err_code = NRFX_ERROR_INVALID_STATE;
    }
    else if (m_cb.low_power_mode)
    {
        nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
    }
    else
    {
        nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);
    }

    NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
    return err_code;
}

There is the if statement if (m_cb.adc_state != NRF_SAADC_STATE_BUSY) but should it not be if (m_cb.adc_state == NRF_SAADC_STATE_BUSY) ?

Because if the ADC is busy then it will start an adc sampling, while you would expect when it is busy it should not and vica versa.

When I enter the function, the state is NRF_SAADC_STATE_IDLE.

Parents
  • Never mind, I used direct register acces to setup the SAADC, for me like this is easier, than I don't have to figure out how the function are working in nrf_saadc.c

    It is not completely finished, but an example as reference for others how I did it (partly used from the bluefruit Arduino library from Adafruit):

    Initialisation:

      NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Over8x;
      NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_14bit;
      NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
    
      NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput3;
      NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELP_PSELP_NC;
      
      NRF_SAADC->CH[0].CONFIG = ((SAADC_CH_CONFIG_RESP_Bypass       << SAADC_CH_CONFIG_RESP_Pos)   & SAADC_CH_CONFIG_RESP_Msk)
                                | ((SAADC_CH_CONFIG_RESP_Bypass     << SAADC_CH_CONFIG_RESN_Pos)   & SAADC_CH_CONFIG_RESN_Msk)
                                | ((SAADC_CH_CONFIG_GAIN_Gain1_5    << SAADC_CH_CONFIG_GAIN_Pos)   & SAADC_CH_CONFIG_GAIN_Msk)
                                | ((SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
                                | ((SAADC_CH_CONFIG_TACQ_15us       << SAADC_CH_CONFIG_TACQ_Pos)   & SAADC_CH_CONFIG_TACQ_Msk)
                                | ((SAADC_CH_CONFIG_MODE_SE         << SAADC_CH_CONFIG_MODE_Pos)   & SAADC_CH_CONFIG_MODE_Msk)
                                | ((SAADC_CH_CONFIG_BURST_Enabled   << SAADC_CH_CONFIG_BURST_Pos)   & SAADC_CH_CONFIG_BURST_Msk);
     
      NRF_SAADC->RESULT.PTR = (uint32_t)&value;
      NRF_SAADC->RESULT.MAXCNT = 1; // One sample
    
      NRF_SAADC->INTENSET = (SAADC_INTENSET_STOPPED_Set <<  SAADC_INTENSET_STOPPED_Pos) & SAADC_INTENSET_STOPPED_Msk;
      NRF_SAADC->INTENSET = (SAADC_INTENSET_STARTED_Set <<  SAADC_INTENSET_STARTED_Pos) & SAADC_INTENSET_STARTED_Msk;
    
    
      NRF_SAADC->INTENSET = (SAADC_INTENSET_END_Set <<  SAADC_INTENSET_END_Pos) & SAADC_INTENSET_END_Msk;
    
      NRFX_IRQ_PRIORITY_SET(SAADC_IRQn, 2);
      NRFX_IRQ_ENABLE(SAADC_IRQn);
    
      NRF_SAADC->TASKS_START = 0x01UL;

    Interrupt (not finished yet):

    void nrfx_saadc_irq_handler(void)
    {
    
      //saadc_temp =(void*)&NRF_SAADC;
    
    
      if (NRF_SAADC->EVENTS_STARTED)
      {
        NRF_SAADC->EVENTS_STARTED = false;
        //take one sample
         NRF_SAADC->TASKS_SAMPLE = 0x01UL;
    
      }
      if (NRF_SAADC->EVENTS_DONE)
      {
          NRF_SAADC->EVENTS_DONE = false;
          NRF_LOG_DEBUG("SAADC Event Done");
      }
      if (NRF_SAADC->EVENTS_END)
        {
            NRF_SAADC->EVENTS_END = false;
            NRF_LOG_DEBUG("SAADC Event End");
    
            if(NRF_SAADC->STATUS) 
            {
             NRF_LOG_DEBUG("SAADC Busy");
             
            }
            
            NRF_SAADC->TASKS_STOP = true;  
        }
    
        if(NRF_SAADC->EVENTS_STOPPED)
        {
          NRF_SAADC->EVENTS_STOPPED = false;
          
          //start new conversion ?
          NRF_SAADC->TASKS_START = 0x01UL;
        }
       
       
       
       
        //NRF_SAADC->EVENTS_END = false;
        //NRF_SAADC->EVENTS_STARTED = false;
       // NRF_SAADC->EVENTS_STOPPED = false;
        //NRF_SAADC->EVENTS_RESULTDONE = false;
    
    }

    In the interrupt I want to change from channel to channel, I need this because I have a 74HC4051 analog multiplexer to get some extra channels, in the interrupt I will change the pins that controlling the inputs of the 47HC4051.

Reply
  • Never mind, I used direct register acces to setup the SAADC, for me like this is easier, than I don't have to figure out how the function are working in nrf_saadc.c

    It is not completely finished, but an example as reference for others how I did it (partly used from the bluefruit Arduino library from Adafruit):

    Initialisation:

      NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Over8x;
      NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_14bit;
      NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
    
      NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput3;
      NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELP_PSELP_NC;
      
      NRF_SAADC->CH[0].CONFIG = ((SAADC_CH_CONFIG_RESP_Bypass       << SAADC_CH_CONFIG_RESP_Pos)   & SAADC_CH_CONFIG_RESP_Msk)
                                | ((SAADC_CH_CONFIG_RESP_Bypass     << SAADC_CH_CONFIG_RESN_Pos)   & SAADC_CH_CONFIG_RESN_Msk)
                                | ((SAADC_CH_CONFIG_GAIN_Gain1_5    << SAADC_CH_CONFIG_GAIN_Pos)   & SAADC_CH_CONFIG_GAIN_Msk)
                                | ((SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
                                | ((SAADC_CH_CONFIG_TACQ_15us       << SAADC_CH_CONFIG_TACQ_Pos)   & SAADC_CH_CONFIG_TACQ_Msk)
                                | ((SAADC_CH_CONFIG_MODE_SE         << SAADC_CH_CONFIG_MODE_Pos)   & SAADC_CH_CONFIG_MODE_Msk)
                                | ((SAADC_CH_CONFIG_BURST_Enabled   << SAADC_CH_CONFIG_BURST_Pos)   & SAADC_CH_CONFIG_BURST_Msk);
     
      NRF_SAADC->RESULT.PTR = (uint32_t)&value;
      NRF_SAADC->RESULT.MAXCNT = 1; // One sample
    
      NRF_SAADC->INTENSET = (SAADC_INTENSET_STOPPED_Set <<  SAADC_INTENSET_STOPPED_Pos) & SAADC_INTENSET_STOPPED_Msk;
      NRF_SAADC->INTENSET = (SAADC_INTENSET_STARTED_Set <<  SAADC_INTENSET_STARTED_Pos) & SAADC_INTENSET_STARTED_Msk;
    
    
      NRF_SAADC->INTENSET = (SAADC_INTENSET_END_Set <<  SAADC_INTENSET_END_Pos) & SAADC_INTENSET_END_Msk;
    
      NRFX_IRQ_PRIORITY_SET(SAADC_IRQn, 2);
      NRFX_IRQ_ENABLE(SAADC_IRQn);
    
      NRF_SAADC->TASKS_START = 0x01UL;

    Interrupt (not finished yet):

    void nrfx_saadc_irq_handler(void)
    {
    
      //saadc_temp =(void*)&NRF_SAADC;
    
    
      if (NRF_SAADC->EVENTS_STARTED)
      {
        NRF_SAADC->EVENTS_STARTED = false;
        //take one sample
         NRF_SAADC->TASKS_SAMPLE = 0x01UL;
    
      }
      if (NRF_SAADC->EVENTS_DONE)
      {
          NRF_SAADC->EVENTS_DONE = false;
          NRF_LOG_DEBUG("SAADC Event Done");
      }
      if (NRF_SAADC->EVENTS_END)
        {
            NRF_SAADC->EVENTS_END = false;
            NRF_LOG_DEBUG("SAADC Event End");
    
            if(NRF_SAADC->STATUS) 
            {
             NRF_LOG_DEBUG("SAADC Busy");
             
            }
            
            NRF_SAADC->TASKS_STOP = true;  
        }
    
        if(NRF_SAADC->EVENTS_STOPPED)
        {
          NRF_SAADC->EVENTS_STOPPED = false;
          
          //start new conversion ?
          NRF_SAADC->TASKS_START = 0x01UL;
        }
       
       
       
       
        //NRF_SAADC->EVENTS_END = false;
        //NRF_SAADC->EVENTS_STARTED = false;
       // NRF_SAADC->EVENTS_STOPPED = false;
        //NRF_SAADC->EVENTS_RESULTDONE = false;
    
    }

    In the interrupt I want to change from channel to channel, I need this because I have a 74HC4051 analog multiplexer to get some extra channels, in the interrupt I will change the pins that controlling the inputs of the 47HC4051.

Children
  • Hello Gatze,

    Thank you for your patience with this.

    There is the if statement if (m_cb.adc_state != NRF_SAADC_STATE_BUSY) but should it not be if (m_cb.adc_state == NRF_SAADC_STATE_BUSY) ?

    Because if the ADC is busy then it will start an adc sampling, while you would expect when it is busy it should not and vica versa.

    I concur that this might look a little off, but you will need to have provided a buffer for the SAADC before calling the nrfx_saadc_sample function, and in doing so the driver will set the state to busy prior to the nrfx_saadc_sample call,

    Gatze said:

    Never mind, I used direct register acces to setup the SAADC, for me like this is easier, than I don't have to figure out how the function are working in nrf_saadc.c

    It is not completely finished, but an example as reference for others how I did it (partly used from the bluefruit Arduino library from Adafruit):

    I am glad to hear that you got the intended functionality with the bare-metal approach.
    You might find this github repository helpful if you intend to keep working with the peripherals through direct register manipulation rather than using the drivers.
    It contains some bare-metal implementations of different peripheral examples.

    Best regards,
    Karl

  • That Github repository is indeed a good resource thank you for that and the answer. That radio example is also interesting, without any protocol looks like. From my time working with Microchip AVR I did almost alway's the bare approach. Anyway, thank you and have already a good weekend.

  • That Github repository is indeed a good resource thank you for that and the answer.

    I am glad to hear that you found my comment useful!

    That radio example is also interesting, without any protocol looks like. From my time working with Microchip AVR I did almost alway's the bare approach.

    Yes, the radio peripheral may be used as any of the other peripherals - so you may use it for proprietary protocols. I would however not really recommend this, since most of this work is already done for you by the SoftDevice (for BLE or ANT) or through the Shockburst or Gazell proprietary protocols.

    I personally also preferred direct register manipulation when I worked with AVR in the past - so I definitely understand your approach to this -, but since changing to Nordic I have had a change of hearts in this regard - now I first and foremost make use of the provided drivers, and really only ever do the register approach to conduct specific tests of non-standard usage, for the most part.

    Anyway, thank you and have already a good weekend.

    Thank you for saying that, I hope you have a great weekend as well!

    Best regards,
    Karl

Related