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

How to use SAADC example on nrf52832 with Zephyr

Hi guys,

I am using the Nordic nrf52832 board for my project. One of my goals is to enable the device to read the voltage from the external source. I have already found an SAADC example where they implemented this function, but now I have some questions related to that example and that function. First, can I use this example together with Zephyr RTOS or maybe you can provide me some new example for that. Also, in case when I need to read the voltage from the external source, can I use minicom and how can I enable the terminal to get this information (voltage value). I found that people used different pins in this case to read the voltage (VDD, GND and P0.03 or P0.02)?

I also need to read the sensor data for temperature and humidity. For that I have DHT22 sensor and I have already found the example in the Zephyr examples, but every time I got very high values for both parameters (in this case I use VDD, GND and P0.11 pins). Do I maybe need to change the code or I just missed the right pin for DATA?

I send you my code for SAADC example and hope that you can help me!!

Thanks a lot in advance and nice day!!

#include <nrf.h>

int main(void)
{
  volatile int16_t result = 0;
  volatile float precise_result = 0;

  // Start HFCLK from crystal oscillator, this will give the SAADC higher accuracy
  NRF_CLOCK->TASKS_HFCLKSTART = 1;
  while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
  NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;

  // Configure SAADC singled-ended channel, Internal reference (0.6V) and 1/6 gain.
  NRF_SAADC->CH[0].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_3us        << SAADC_CH_CONFIG_TACQ_Pos);

  // Configure the SAADC channel with VDD as positive input, no negative input(single ended).
  NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_VDD << SAADC_CH_PSELP_PSELP_Pos;
  NRF_SAADC->CH[0].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;

  // No automatic sampling, will trigger with TASKS_SAMPLE.
  NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos;

  // 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));

  // 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;

  // 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
  precise_result = (float)result / 4551.1f;
  precise_result; // to get rid of set but not used warning

  // 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();
  }
}

  • Thanks a lot. I will take a look and try to find some solution. Also, related to this temperature sensor I found this defined example what do you think about that. I connected the sensor to my device using (VDD, GND and P0.11 pins), but I got some weird results for temperature and humidity. What do you suggest me here, maybe I missed this analog pin (P0.11)?? Thanks in advance!!

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr.h>
    #include <device.h>
    #include <drivers/sensor.h>
    #include <stdio.h>
    
    static const char *now_str(void)
    {
    	static char buf[16]; /* ...HH:MM:SS.MMM */
    	u32_t now = k_uptime_get_32();
    	unsigned int ms = now % MSEC_PER_SEC;
    	unsigned int s;
    	unsigned int min;
    	unsigned int h;
    
    	now /= MSEC_PER_SEC;
    	s = now % 60U;
    	now /= 60U;
    	min = now % 60U;
    	now /= 60U;
    	h = now;
    
    	snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u",
    		 h, min, s, ms);
    	return buf;
    }
    
    void main(void)
    {
    	const char *const label = DT_LABEL(DT_INST(0, aosong_dht));
    	struct device *dht22 = device_get_binding(label);
    
    	if (!dht22) {
    		printf("Failed to find sensor %s\n", label);
    		return;
    	}
    
    	while (true) {
    		int rc = sensor_sample_fetch(dht22);
    
    		if (rc != 0) {
    			printf("Sensor fetch failed: %d\n", rc);
    			break;
    		}
    
    		struct sensor_value temperature;
    		struct sensor_value humidity;
    
    		rc = sensor_channel_get(dht22, SENSOR_CHAN_AMBIENT_TEMP,
    					&temperature);
    		if (rc == 0) {
    			rc = sensor_channel_get(dht22, SENSOR_CHAN_HUMIDITY,
    						&humidity);
    		}
    		if (rc != 0) {
    			printf("get failed: %d\n", rc);
    			break;
    		}
    
    		printf("[%s]: %.1f Cel ; %.1f %%RH\n",
    		       now_str(),
    		       sensor_value_to_double(&temperature),
    		       sensor_value_to_double(&humidity));
    		k_sleep(K_SECONDS(2));
    	}
    }

Related