Arduino-esp32 course – General-purpose input/output (GPIO) – Chapter 3

I want to state here that I’m not an electronics engineer and I know the basics only after years of tinkering and because I use to soldier PCBs for my father since I’m 8 or so. So if there is anything that is not correctly explained just comment and I will try to document it better.
The ESP8266 has 17 GPIO pins (0-16), however, you can only use 11 of them, because 6 pins (GPIO 6 – 11) are used to connect the flash memory chip.
The ESP32 chip has 40 physical GPIO pins. Not all of them can be used and some of them are only input GPIOs meaning you cannot use them for output communication (Refer to your board tech specs fot that) According to Espressif documentation on the ESP32:

  • GPIO 6-11 are usually used for SPI flash.
  • GPIO 34-39 can only be set as input mode and do not have software pullup or pulldown functions.

Electronics ABC
pull-up resistor connects unused input pins to the dc supply voltage, (3.3 Vcc in ESP32) to keep the given input HIGH
pull-down resistor connects unused input pins to ground, (GND 0V) to keep the given input LOW.
Analog-to-Digital Converter (ADC)
The Esp32 integrates 12-bit ADCs and supports measurements on 18 channels (analog-enabled pins). The Ultra low power (ULP-coprocessor) in the ESP32 is also designed to measure voltages while operating in sleep mode, which allows for low power consumption.
Digital-to-Analog Converter (DAC)
Two 8-bit DAC channels can be used to convert two digital signals to two analog voltage outputs. These dual DACs support the power supply as an input voltage reference and can drive other circuits. Dual channels support independent conversions.

A detailed walkthrough over GPIOs and electronics is out-of-scope in this blog post series since it’s a thema on it’s own and I think a engineer could be the best suited to expand on this properly. There are many instructables and videos about it if you are interested in researching more.

So now back to ESP32 Arduino framework coding, let’s use this GPIO information, to declare one as output and blink a LED.

#include "Arduino.h"
// HINT: Many ESP32 boards have an internal LED on GPIO5
// If it's on another PIN just change it here:
int ledGpio = 5; 

void setup() { 
  Serial.begin(115200);
  Serial.println("Hello blinking LED");
  pinMode(ledGpio, OUTPUT);
} 
void loop() { 
  digitalWrite(ledGpio, HIGH); 
  delay(500); 
  digitalWrite(ledGpio, LOW); 
  delay(200); 
}

As a good reference here is the pinMode entry in Arduino documentation. modes can be:

  • INPUT
  • OUTPUT
  • INPUT_PULLUP

This very short program will just set the GPIO5 in output mode and in the loop just turn it HIGH(1) and send 3.3V to the GPIO or LOW(0). Keep in mind that the ESP32 can draw a max. consumtion of about 10 mA per GPIO so always use a resistance (10K or similar) if you connect your own LED or you may damage the board.
Now seeing that the GPIO state is 1 or 0, we can also write this program in a shorter way, let’s give it a second round:

include "Arduino.h"
int ledGpio = 25;
bool ledState = 0; // New bool variable
void setup() {
  pinMode(ledGpio, OUTPUT);
}
void loop() {
  digitalWrite(ledGpio, ledState);
  ledState = !ledState;
  delay(20);
}

We are just doing one digitalWrite per loop now and right after that just redeclaring the variable using the logical NOT operator. That way it will flip between 0 and 1, turning the LED on and off quite fast since we added just a 20 millis delay. So fast is almost always on!
So now we are in this point we can start with the next topic that is called pulse width modulation or PWM.

PWM provides the ability to ‘simulate’ varying levels of power by oscillating the output from the microcontroller. By varying (or ‘modulating’) the pulsing width we can effectively control the light output from the LED, hence the term PWM or Pulse Width Modulation. Arduino also had PWM pins with a scale from 0 – 255 so we could have 255 brightness level on a LED.

This PWM image is from Arduino tutorial – credits: https://www.arduino.cc/en/tutorial/PWM

ESP32 / ESP8266 PWM example for one Channel

// Since someone asked about a modern AnalogWrite PWM example
// Just try to compile this one
include "Arduino.h"

// use first channel of 16 channels (started from zero)
define LEDC_CHANNEL_0 0
// use 13 bit precission for LEDC timer
define LEDC_TIMER_13_BIT 13
// use 5000 Hz as a LEDC base frequency
define LEDC_BASE_FREQ 5000
// fade LED PIN (replace with LED_BUILTIN constant for built-in LED)
define LED_PIN 25
bool brightDirection = 0;
int ledBright = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("Hello PWM LED");
  // Setup timer and attach timer to a led pin
  ledcSetup(LEDC_CHANNEL_0, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
  ledcAttachPin(LED_PIN, LEDC_CHANNEL_0);
}
// Arduino like analogWrite: value has to be between 0 and valueMax
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255) {
  // calculate duty, 8191 from 2 ^ 13 - 1
  uint32_t duty = (8191 / valueMax) * min(value, valueMax);
  ledcWrite(channel, duty);
}

void loop() {
  // set the brightness on LEDC channel 0
  ledcAnalogWrite(LEDC_CHANNEL_0, ledBright);
  if (ledBright == 255 || ledBright == 0) {
    brightDirection = !brightDirection;
  }
  if (brightDirection) {
    ++ledBright;
  } else {
    --ledBright;
  }
  delay(15);
  Serial.println(ledBright);
}

The ESP32 has a PWM controller with 16 independent channels that can be configured to generate PWM signals with different properties. Just wanted to mention this possibility but I’m not going to extend myself in this topic since they are hundred of pages that explain it much better than I could do. Please check https://randomnerdtutorials.com/esp32-pwm-arduino-ide to have a nice PWM example.

Keep tuned and follow this blog to get more. In next chapter we are going to explore I2C communication and connect a thermometer to our ESP32 to display via Serial the room temperature.

ESP-IDF Libraries in Arduino framework

I started to dig a bit more into the Iot development network from Espressif with the intention to slowly learn something new. All the official examples of Mesh lights, ESP32-Camera and ESP-WHO that presents a preliminary version of face recognition are built on the top of the IDF.

So sooner or later, I think will be the official way to do “internet of the things” devices with these Boards. But I’m still not ready for it, I need to do simple examples and experimenting before taking over and do something for real.

So the first things I tackled on is to take this libraries “as is” and use them in existing Arduino framework projects. And it’s fully possible, below is a small example about this using the TTGO Camera with Pir sensor

https://github.com/martinberlin/esp32-camera-bme280

So far it features:

  • camera_index.html template loaded from the SPIFFS so you can modify it for your project (No Gziped non-editable file)
  • Added V-Flip setting that was not existing in the original example
  • Libraries loaded using platform.io file

This is my humble try to make a hackeable and modificable esp32 Camera example using ARDUINO as a framework but with the official Espressif Camera Libraries.

One important step is that without using the IDF, just adding the libraries in plataform.io project configuration file:

platform = espressif32
framework = arduino

lib_deps =
https://github.com/espressif/esp32-camera.git

It won’t compile. The reason is that it tries to find the C header files but they do not have the needed mapping out of the box if you use framework: arduino. It will complain that:

Compiling .pioenvs/ttgo-lora32-v1/libe0c/esp32-camera/conversions/jpge.cpp.o
.piolibdeps/esp32-camera/conversions/jpge.cpp:11:18: fatal error: jpge.h: No such file or directory

And the file is there but in another directory. So my workaround was to add this directory in the build_flags configuration:

build_flags =
-I.piolibdeps/esp32-camera/conversions/private_include
-I.piolibdeps/esp32-camera/sensors/private_include
-I.piolibdeps/esp32-camera/driver/private_include

After this it compiles without errors.

Some notes and references for this post

Think about C header files as your interfaces, your function prototypes! Code organization is very important.
3D-models for the TTGO Cameras available in Thingiverse, my own prototype design (be aware!)

New ESP-Mesh RGB+White Light soldered. You can do your own for about 10€ materials and 2 hours soldiering ;)
Small preview:

The ESP–IDF epaper component for ESP32

The development + testing is happening in this repository:
github.com/martinberlin/cale-idf

If you want to use this as a component in your existing project: github.com/martinberlin/CalEPD