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

How do I use registers to configure SAADC for my Arduino Nano 33?

The documentation is a little unclear. I am using Arduino Nano 33 BLE. Using the analogread() functions of Arduino I get a much worse performance than the nRF is supposed to handle. How can I use the registers with the void setup() and void loop() to leverage the full performance of SAADC? 

I am using Arduino on PlatformIO IDE on VSCode. 

This is the closest think I have found: https://github.com/andenore/NordicSnippets/blob/master/examples/saadc/main.c 

But it is not working as I am too inexperienced to figure out the GPIO. 

  • Thank you but I do not know how to make it work with Arduino yet. Any suggestions?

  • Sorry, I don't use Arduino nor PlatformIO and I don't think Arduino is recommended for BLE firmware development.  You can take the required files and try to add it to your VS code and compile.  Or you can also follow the blog posts here to work with that code

    https://embeddedsoftdev.blogspot.com/p/ehal-nrf51.html

    https://embeddedsoftdev.blogspot.com/2017/12/bluetooth-le-with-nordic-nrf51-nrf52.html

  • #include <Arduino.h>
    #include <nrf.h>
    
     uint32_t result = 0;
     uint32_t result_channel;
     uint32_t amount =0;
      float precise_result = 0;
    
    void setup() {
    
      Serial.begin(9600);
    
      // Configure SAADC singled-ended channel, Internal reference (0.6V) and 1/6 gain.
      NRF_SAADC->CH[1].CONFIG = (SAADC_CH_CONFIG_GAIN_Gain1_6    << SAADC_CH_CONFIG_GAIN_Pos) |
                                (SAADC_CH_CONFIG_MODE_SE         << SAADC_CH_CONFIG_MODE_Pos) |
                                (SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) |
                                (SAADC_CH_CONFIG_RESN_Bypass     << SAADC_CH_CONFIG_RESN_Pos) |
                                (SAADC_CH_CONFIG_RESP_Bypass     << SAADC_CH_CONFIG_RESP_Pos) |
                                (SAADC_CH_CONFIG_TACQ_20us        << SAADC_CH_CONFIG_TACQ_Pos);
    
      // Configure the SAADC channel with VDD as positive input, no negative input(single ended).
      NRF_SAADC->CH[1].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput1 << SAADC_CH_PSELP_PSELP_Pos;
      NRF_SAADC->CH[1].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;    
    
        // Configure the SAADC resolution.
      NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_14bit << SAADC_RESOLUTION_VAL_Pos;
    
        // Configure result to be put in RAM at the location of "result" variable.
      NRF_SAADC->RESULT.MAXCNT = 1;
      //NRF_SAADC->RESULT.PTR = (uint32_t)&result;
    
      // Enable SAADC (would capture analog pins if they were used in CH[0].PSELP)
      NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos;
    
      // Calibrate the SAADC (only needs to be done once in a while)
      NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;
      while (NRF_SAADC->EVENTS_CALIBRATEDONE == 0);
      NRF_SAADC->EVENTS_CALIBRATEDONE = 0;
      while (NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy <<SAADC_STATUS_STATUS_Pos));
    
      NRF_SAADC->SAMPLERATE=0x20<<SAADC_SAMPLERATE_CC_Msk;
    
        // Start the SAADC and wait for the started event.
      NRF_SAADC->TASKS_START = 1;
      while (NRF_SAADC->EVENTS_STARTED == 0);
      NRF_SAADC->EVENTS_STARTED = 0;    
        //Do a SAADC sample, will put the result in the configured RAM buffer.
      NRF_SAADC->TASKS_SAMPLE = 1;
      while (NRF_SAADC->EVENTS_END == 0);
      NRF_SAADC->EVENTS_END = 0;
                        
    }
    
    
    void loop() {
      
      Serial.println("Measure");
    
      // Convert the result to voltage
      // Result = [V(p) - V(n)] * GAIN/REFERENCE * 2^(RESOLUTION)
      // Result = (VDD - 0) * ((1/6) / 0.6) * 2^14
      // VDD = Result / 4551.1
      result =NRF_SAADC->RESULT.PTR;
      result_channel = result & 0x0000FFFF;
      precise_result =result_channel/4551.1;
    
      Serial.println("===============");
      // Serial.println(SAADC_CH_PSELN_PSELN_AnalogInput0);
      Serial.println(result,HEX);
      Serial.println(precise_result);
      Serial.println(NRF_SAADC->RESULT.AMOUNT);
      Serial.println();
    
    
      // //Stop the SAADC, since it's not used anymore.
      // NRF_SAADC->TASKS_STOP = 1;
      // while (NRF_SAADC->EVENTS_STOPPED == 0);
      // NRF_SAADC->EVENTS_STOPPED = 0;
    
      //   while (1)
      // {
      //   __WFE();
      // }
    
    
    }

    This is my code so far but I only get 0. I have checked the pin numbers and all is where it should be. I do not know what is wrong. I am using Arduino Nano BLE 33

  • Hi,

    The main problem is that you are not setting NRF_SAADC->RESULT.PTR, but you are trying to read out the result directly from this register. The SAADC peripheral uses EasyDMA to store samples directly into a RAM buffer. You need to set the buffer before starting sampling. If you do not do this, the SAADC peripheral will try to store samples in the address of the PTR reset value (0x00000000) (which is in flash - overlapping with the application code, not RAM), hence it will fail. You can use this example as a reference code for your application.

    Best regards,
    Jørgen

Related