EMB2: Using a digital potentiometer

Digital potentiometer DS1803 is an I2C-controlled device that can digitally control the potentiometer.
Opposite to the physical potentiometers, there are no movable parts.
DS1803 has two digital potentiometers controlled independently. We use just one with the lower cardinal number (index 0). In our example, it is a 100k spread between GND and VCC, and its output is connected to the ADC (analogue to digital converter) input of the ESP32 MCU. This way, the potentiometer's wiper is controlled remotely via the I2C bus.
The device's I2C address is 0x28, and the ADC input GPIO pin is 7.
The digital potentiometer in our laboratory node forms then a loopback device: it can be set (also read) via I2C, and the resulting voltage can be measured on the separate PIN (ADC) 1. This way, it is possible, e.g. to draw a relation between the potentiometer setting and ADC readings to check whether it is linear or forms some other curve.

 Digital potentiometer DS1803 application in VREL Next Gen nodes
Figure 1: Digital potentiometer DS1803 application in VREL Next Gen nodes
The potentiometer has an 8-bit resolution, so the resistance step is 100k/256=~390 ohm.

Reading of the ADC is possible using the regular analogRead(pin) function.

In ESP32, ADC has by default a 12-bit resolution, so valid return values are 0…4095;


To implement this scenario, it is advised to get familiar with at least one of the following scenarios first:

They enable you to present the data on the display (i.e. readings).

To handle communication with the DS1803 digital potentiometer, we use bare I2C programming. For this reason, we need to include only the I2C protocol library:

#include <Wire.h>
Also, remember to add the display handling library, as present in the scenarios. We suggest using OLED or ePaper to present the relation between the setting and reading as a graphic or even more than one display (e.g. LCD + OLED) to handle readings and the graph.

Below, we present a sample control library that you need to include in your code:

enum POT_LIST {POT_1 = 0xA9, POT_2=0xAA, POT_ALL=0xAF}; //We have only POT_1 connected
typedef enum POT_LIST POT_ID;
void setPotentiometer(TwoWire&  I2CPipe, byte potValue, POT_ID potNumber);
byte readPotentiometer(TwoWire& I2CPipe, POT_ID potNumber);
void setPotentiometer(TwoWire& I2CPipe, byte potValue, POT_ID potNumber)
byte readPotentiometer(TwoWire& I2CPipe, POT_ID potNumber) //reads selected potentiometer
  byte buffer[2];  
  return (potNumber==POT_1?buffer[0]:buffer[1]);
In the library above, the readPotentiometer(…) function returns a value previously set to the digital potentiometer, not an actual ADC voltage reading! It returns a set value by setPotentiometer(…), which is on the “digital” side of the DS1803 device. Actual ADC reading can be obtained using analogRead(pin).

Suggested Readings and Knowledge Resources

Hands-on Lab Scenario

Task to be implemented

Iterate over the potentiometer settings, read related voltage readings via ADC, and present them in graphical form (as a plot). As the maximum resolution is 256, you can use a plot of 256 points or any other lower value covering all ranges. Present graph (plot) on either ePaper or OLED display, and while doing the readings, you should present data in the LCD (upper row for a set value, lower for a reading of the ADC).


Check if you can see all the displays. Remember to use potentiometer 1 (index 0) because only this one is connected to the ADC input of the ESP32 MCU. In these steps, we present only how to handle communication with a digital potentiometer and how to read the ADC input of the MCU. Methods for displaying the measurements and plotting the graph are present in other scenarios. Remember to include the functions above in your code unless you want to integrate them with your solution.


Below, we assume that you have embedded functions handling operations on the digital potentiometer as defined above in your source file. Remember to add Wire.h include!

Note: Step 5 presents some stub code for displaying data on an OLED display.

Step 1

Define I2C bus GPIOs: clock (SCL) uses GPIO 4 and data (SDA) GPIO 5. ADC uses GPIO 7. Digital potentiometer chip DS1803 uses 0x28 I2C address. All definitions are present in the following code:

#define SCL 4
#define SDA 5
#define POT_ADC 7
#define DS1803_ADDRESS 0x28

Step 2

Declare an array of readings that fits an OLED display. Adjust for ePaper resolution (horizontal) if using it. OLED is 128×128 pixels:

static int16_t aGraphArray[128]; 

Step 3

Include functions present in the PREREQUISITES section.

Step 4

Initialise the I2C bus and configure ADC's GPIO as input:

  pinMode(POT_ADC, INPUT);

Step 4

Read the loopback characteristics of the digital potentiometer to ADC loop and store it in the array:

for(byte i=0; i<128; i++)
    setPotentiometer(I2CPipe, 2*i, POT_1); 

Step 5

Display on the OLED. Assume the following handler to the pointer to the display controller class:

SSD1306Wire& display

More information in the scenario EMB7: Using OLED display. Note, ADC measures in the 12-bit mode (we assume such configuration, adapt factor if using other sampling resolution), so values stored in an aGraphArray array are between 0 and 4095.

 float factor = 63./4095.;
 for(byte x=0;x<128;x++)
    int16_t y=63-round(((float)aGraphArray[x])*factor);

Result validation

A relation between the potentiometer set value and ADC reading should be almost linear from 0V up to about 3V. It becomes horizontal because the ESP32 chip limits the ADC range to 3V, so going beyond 3V (and due to the electronic construction as in figure 1 it may go to about 3.3V) gives no further increase but rather a reading of the 4096 value (which means the input voltage is over the limit). For this reason, your plot may be finished suddenly with a horizontal instead of linearity decreasing function. It is by design. ADC input of the ESP32 can tolerate values between 3V and 3.3V. The linear correlation mentioned above is never perfect, either because of the devices' implementation imperfection (ESP32's ADC input and digital potentiometer output) or because of the electromagnetic noise. There are many devices in our lab room.


The ADC readings are changing slightly, but I have not changed the potentiometer value. What is going on?: The ADC in ESP32 is quite noisy, mainly when using WiFi parallelly. Refer to the Coursebook and ESP32 documentation on how to increase measurement time that will make internally many readings and return to you an average. Use the analogSetCycles(cycles) function to increase the number of readings for the averaging algorithm. The default is 8, but you can increase it up to 255. Note that the higher the cycles parameter value, the longer the reading takes, so tune your main loop accordingly, particularly when using an asynchronous approach (timer-based). Eventually, you can implement low-pass filters yourself (in the software).

Project information

This Intellectual Output was implemented under the Erasmus+ KA2.
Project IOT-OPEN.EU Reloaded – Education-based strengthening of the European universities, companies and labour force in the global IoT market.
Project number: 2022-1-PL01-KA220-HED-000085090.

Erasmus+ Disclaimer
This project has been funded with support from the European Commission.
This publication reflects the views of only the author, and the Commission cannot be held responsible for any use that may be made of the information contained therein.

Copyright Notice
This content was created by the IOT-OPEN.EU Reloaded consortium, 2022,2024.
The content is Copyrighted and distributed under CC BY-NC Creative Commons Licence, free for Non-Commercial use.

en/iot-open/practical/hardware/sut/esp32/emb2_1.txt · Last modified: 2024/04/20 08:19 by pczekalski
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0