What is ADC and How does it work?

The ADC is basically a system that converts an analog signal, such as sound, temperature, wind-speed, orientation, angular-motion, and many more into binary bit streams. The process of converting this information from one form into another can be seen in many aspects of our daily lives – for example: when we convert what we hear on the radio (analog) into music files stored away on your computer’s hard drive and then back again so you can listen via headphones!.

Another Example is Phone camera converts the image sensor values into digital image file. Same Process is reversed when an image is displayed back on a screen.

A Complex example of ADC is used in Car-Engine when hundreds of Engine parameters are measured via Analog sensors and converted into binary data and sent to the Engine Control Unit for processing.

ADC has 3 functioning steps.

  1. Analog Sensitivity of ADC Pin How small voltage signal/value can be detected on the MCU -ADC Pin.
  2. Converting Analog value into 8-12bits binary Data.
  3. Sample Rate.
10.01411814.11765mv
20.02823528.23529mv
30.04235342.35294mv
40.05647156.47059mv
50.07058870.58824mv
60.0847084.70588mv

ADC is specified as 8-bit, 10-bit, 12-bit. Any Analog data needs to be converted into bit streams. Say 0 to 3.3V needs to be measured in 8 bits.

8 bits of ADC data = Maps Vin in 255 values.[0V -3.3/3.5/5V]

So, 1-bit value = 3.3/255 = 0.01294 v = 12.9 mV. This means an 8-bit ADC is sensitive enough to measure 12.9mV value at ADC. 

How to interpret the value.

Say A temperature Sensor Can read values between 0-100C. The same value is translated into 0-3.3V range.

A 8-bit ADC can quantize   100/255 =0.392 Degree Centigrade as a single bit.

Similarly, a 10-bit ADC can read 100/1023 = 0.0977C.

Conclusion “ Higher the ADC bits more Sensitive and read low value readings.”

 ADC is also defined by the sampling rate. How frequently you can read/sense the pin data. It can be as low as 100 Hz and as high as 40Mhz. To 

Can you Measure Negative voltage on ADC?

ADCs are designed to detect Voltage range between 0(GND) and Vcc. Any Negative Voltage could damage your ADC module or the complete MCU. But there is a way to measure the Negative Voltage. For example, if you want to sample a sine wave [-2v to +2v] then You should put a voltage- divider Circuit before your MCU-ADC Pin. <<Add a Voltage Divider link here.>>

What is DAC and How does it work?

Digital to Analog Converters works by converting the digital value into analog. The range of Analog value is defined by  Digital-Val x  (Vref/2^n)

Where Vref is the input voltage at the power supply in 3.3V,3.6V or 5V. 

N: represents the number of SAR Bits.

Why do we need ADC and DAC?

We need ADC to convert an analog Data from sensors into a Digital input which can be then used by Microcontrollers to Process the Data. Since MPUs understand only binary data-formats.

source: Link

Vice-versa When Microcontroller wants to send some Digital Output DAC converts Digital output to Analog voltage output which is understood by Analog Circuit.

ADC read operation generates interrupt, can take upto tens of microseconds. 

PS: Now many Sensors with Analog inputs have an inbuilt ADC & DAC input which are calibrated for optimum performance and they interface via I2C/SPI.

Sensors and Device List using ADC/DAC

    AD5171 Digital Potentiometer// add the exact model number.

MPL3115A2 //add the exact model number

    Temperature Sensor: KY-013 or AD7418ARZ

Humidity Sensor: AM2302/DHT22. //add the exact model number

    Gyroscopes & Accelerometers use the 

Voltage Divider Circuit 

Voltage Divider circuit. For ADC.

Source: Link

Voltage Divider Circuit for DAC

Source: Link

ADC and DAC Module in MicroPython

The DAC is used to output analog values (a specific voltage) on pin X5 or pin X6. The voltage will be between 0 and 3.3V.

Example Code:

import math

from pyb import DAC

# create a buffer containing a sine-wave

buf = bytearray(100)

for i in range(len(buf)):

    buf[i] = 128 + int(127 * math.sin(2 * math.pi * i / len(buf)))

# output the sine-wave at 400Hz

dac = DAC(1)

dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)

The above code will output a sine wave

How to Debug ADC and DAC

ADC can be sensitive to noise leading to large discrepancies in ADC readings. To minimize noise, users may connect a 0.1 µF capacitor to the ADC input pad in use. Multisampling may also be used to further mitigate the effects of noise.

Calibration: It is a good practice to add a 0.1uf Capacitor before the ADC pin. This helps in filtering out the noise and any static dv voltage built-up

Concurrent reading Sampling Multiple values from ADC pins and evaluating  the most concurrent reading and doing an average is a good practice. Especially When the reading values are in low range.

A median Algo is a good start to read the values. 

Copy/Write Error:

Many times, 10 bit or 12-bit ADC  value is read into the u16 datatype. It is good practice to reset the value to 0 after the operation.

Sample over Nyquist rate : If you are doing signal reconstruction and doing some Signal Processing like FFT(MicroPython) . you can refer to this library.

https://github.com/peterhinch/micropython-fourier

ESP32 ADC DAC Programing and Pin Out

Sampling Rate = 6KHz = 6000 samples/sec

Pinout-Diagram

ESP32 has 2 ADC blocks built into the silicon.

ADC1

8 ADC channels 

    GPIO32

    GPIO33

    GPIO34  

    GPIO35

    GPIO36

    GPIO37

    GPIO38

    GPIO39

EACH ADC IS 12-bit ADC by default, can be configured to 10-bit and 11-bit

ADC2

ESP32 ADC Limitations

  • Some of the ADC2 pins are used as strapping pins (GPIO 0, 2, 15) thus cannot be used freely. Such is the case in the following official Development Kits:
  • ESP32 DevKitC: GPIO 0 cannot be used due to external auto program circuits.
  • ESP-WROVER-KIT: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes.
  • Since the ADC2 module is also used by the Wi-Fi, only one of them could get the preemption when using together, which means the adc2_get_raw() may get blocked until Wi-Fi stops, and vice versa.

Sample Code

from machine import Pin, ADC
from time import sleep
import utime
adc_8bit_mask = 0x00ff
adc_10bit_mask = 0x03ff
adc_12bit_mask = 0x0fff
sample_rate=100 #max value 6000
adc_pin = ADC(Pin(34)) #create an adc class object
adc_pin.atten(ADC.ATTN_11DB)       #Full range: 3.3v
 
while True:
  adc_value = adc_12bit_mask and adc_pin.read()
  print(adc_value)
  adc_value = 0 #re-initialize val to zero
  utime.sleep(1/sample_rate)

Sample Output

Arduino ADC and DAC Programming and Pinout.

Sampling rate = 9.6KSPS(9600)

The ADC clock of Atmega328P is 16 MHz divided by a ‘prescale factor’. The prescale is set by default to 128 which leads to 16MHz/128 = 125 MHz ADC clock. Since a single conversion takes 13 ADC clocks, the default sampling rate is ~ 9600 Hz.

PrescaleADC -ClockSampling Rate
Register Value
ADPS2    ADPS1    ADPS0
28615Khz0                0              1
44307Khz0                1              0
82153Khz0                1             1

This the default Sample rate unless the interrupts are disabled and the prescale factor is reduced.

Pinout-Diagram

Sample Code

int analogPin = A3; // potentiometer wiper (middle terminal) connected to analog pin 3
                    // outside leads to ground and +5V
int val = 0;  // variable to store the value read
void setup() {
  Serial.begin(9600);           //  setup serial
}
void loop() {
  val = analogRead(analogPin);  // read the input pin
  Serial.println(val);          // debug value
}

Sample Output

Raspberry Pi PICO ADC and DAC Programming and Pinout.

12-bit ADC

Sample Rate = 500kSPS

Number of ADC Channels = 4

ADC ModulePIN Number
ADC0GP 26
ADC1GP 27
ADC2GP28

Pinout-Diagram

Sample Code

from machine import Pin, ADC
from time import sleep
import utime
adc_8bit_mask = 0x00ff
adc_10bit_mask = 0x03ff
adc_12bit_mask = 0x0fff
 
sample_rate=100 #max value 6000
adc_pin = ADC(Pin(34)) #create an adc class object
 
while True:
  adc_value = adc_12bit_mask and adc_pin.read()
  print(adc_value)
  adc_value = 0 # resetting the value to zero
  utime.sleep(1/sample_rate)

Sample Output

0 0 votes
Article Rating
Previous articleHow to Interface GPIO Using MicroPython
Next articleHow To Interface UART Communication Using MicroPython
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments