Technical Details

ESP32 PLC 21

BACK TO THE PRODUCT

Initial Installation

ARDUINO IDE

Arduino IDE is the original platform to program Arduino boards. This cross-platform application is available on Windows, macOS and Linux under the GNU General Public License. Arduino IDE supports C and C++ code structuring.

Industrial Shields recommends using the Legacy Arduino IDE (1.8.X) to program ESP32 based PLCs, although other ESP compatible software could be used. The Arduino 1.8.X IDE can be downloaded from this link.

After downloading and installing the Arduino IDE, install the industrialshields-esp-32 board package inside the IDE. This can be done by following this tutorial and selecting the industrialshields-esp-32 package in step number 6.

 






Inputs & Outputs

ANALOG INPUTS

Voltage variation between –Vcc (or GND) and +Vcc, can take any value. An analog input provides a coded measurement in the form of a digital value with an N-bit number. In Digital and Analog I/O there is self insulation, so it is possible to connect them using a different power supply from the 24V one.

Inputs: (6x) Analog (0-10Vdc) / Digital (5-24Vdc), configurable by software.

To know more about analog inputs...

TYPICAL CONNECTION

  Analog Input

DIGITAL INPUTS

Voltage variation from –Vcc (or GND) to +Vcc, with no intermediate values. Two states: 0 (-Vcc or GND) and 1 (+Vcc). In Digital and Analog I/O there is self insulation, so it is possible to connect them using a different power supply from the 24V one.

Inputs: (7x) Digital Isolated (5-24Vdc) and (6x) Digital (5-24Vdc), configurable by software.

All digital inputs are PNP.

To know more about digital inputs...

TYPICAL CONNECTIONS

- Digital Isolated Input:

Digital Isolated Input 

- Digital No-Isolated Input:    

Digital No Isolated Input  

INTERRUPT INPUTS

Interrupt Service Routine: ISRs are a mechanism that allows a function to be associated with the occurrence of a particular event. When the event occurs, the processor exits immediately from the normal flow of the PLC program and runs the associated ISR function ignoring any other task.

The pins supporting interrupts are the following:

PLC Pin
ESP32 Pin
0.5
27
0.6
26

No configuration of the external switches is needed to use the interrupts in the ESP32 based PLCs.

To know more about interrupt inputs...

TYPICAL CONNECTION

Interrupt Input

PROGRAM EXAMPLE

In this example the I0.5 pin activates an interrupt every time its state changes, printing a message through the serial.

void setup() {
// Begin serial port
Serial.begin(9600);
  // Set input
  pinMode(I0_5, INPUT);
//Initialize interrupt
attachInterrupt(digitalPinToInterrupt(I0_5), isrI0_5, CHANGE);
}

void loop() {
while(true);
}

void isrI0_5() {
Serial.println("Interrupt activated");
}

Communications

Ethernet

Ethernet is the most commonly used technology in wired local area networks (LANs). A LAN is a network of computers and other electronic devices that covers a small area such as a room, office, or building. It is used in contrast to a wide area network (WAN), which spans over much larger geographical areas. Ethernet is a network protocol that controls how data is transmitted over a LAN. Technically, it is referred to as the IEEE 802.3 protocol. The protocol has evolved and improved over time to transfer data at the speed of a gigabit per second.

The Ethernet port controller included in the ESP based PLCs is the W5500 IC, which is compatible with the Arduino Ethernet2 Shield libraries. It ts a Hardwired TCP/IP embedded Ethernet controller that provides easy internet connection to embedded systems. The W5500 enables users to have internet connectivity in their applications just by using the single chip in which TCP/IP stack, 10/100 Ethernet MAC and PHY embedded. The W5500 chip embeds a 32KB internal memory buffer for the Ethernet packet processing. SPI provided for easy integration with the external microcontroller.

Hardware

Important: Make sure that your ESP32 PLC is properly powered (12-24Vdc). The USB is not capable of properly powering the PLC and the Ethernet communication. There is not any switch or additional configuration needed for the Ethernet communication to work, it should be plug and play.

Software 

Important: Make sure you have the industrialshields-esp-3 board package properly installed in your Arduino IDE.

Once the hardware configuration is done, it is possible to proceed with the software configuration and also its usage. The Ethernet library with all its functions can be used to set up the connection. Just include it in the code this way:

#include <Ethernet.h>

Example codes:

Echo TCP Server
This example sets up a TCP server over Ethernet, which listen to incoming connections from clients and responds to received messages sending them back to the client.
To test the connection with a PC, you can use Netcat to easily connect to the server and send bytes (the Ethernet connection must be set up in your PC). In this case this can be done with this command (note that the IP and port should be the ones used in the code): nc 10.10.10.100 5566.

Arduino code:

#include <Ethernet.h>
// MAC address
byte mac[] = { 0xBE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// IP address
byte ip[] = { 10, 10, 10, 100 };
int tcp_port = 5566;
EthernetServer server = EthernetServer(5566);
void setup()
{
// Initialize the ethernet device
Ethernet.begin(mac, ip);
// Start server for listening for clients
server.begin();
}
void loop()
{
// If an incoming client connects, there will be bytes available to read:
EthernetClient client = server.available();
if (client.available()) {
// Read bytes from the incoming client and write them back
// to the same client connected to the server
client.write(client.read());
}
}

ECHO TCP Client
This example sets up a TCP client over Ethernet, which can be used to connect to the server seen in the previous code. The IP and port the server is listening must be known and configured accordingly in the code. In this case the client sends the received data from the server through the serial port. To test this program with a PC, a TCP server can be opened with Netcat using the next command (the Ethernet connection must be properly set up in your PC to communicate with the ESP32 PLC): nc -l 5566.

Arduino code:

#include <Ethernet.h>

byte mac[] = { 0xBE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 10, 10, 10, 100 };
byte server[] = { 10, 10, 10, 90};
int tcp_port = 5566;
EthernetClient client;
void setup()
{
Ethernet.begin(mac, ip);
Serial.begin(9600);
delay(1000);
Serial.println("Connecting...");
if (client.connect(server, tcp_port)) { // Connection to server
Serial.println("Connected to server");
client.println();
} else {
Serial.println("Connection failed");
}
}
void loop()
{
if (client.available()) {
if(Serial.available()){
char s = Serial.read(); // Read a byte from serial
client.write(s); // Send what is read on serial monitor
char c = client.read(); //read a byte from the server
Serial.print(c); // Print the data received from the server through serial monitor
}
}

if (!client.connected()) {
Serial.println();
Serial.println("Disconnecting.");
client.stop();
while(true);
}
}

To know more about Ethernet communication...

Ethernet with HTTP.
Ethernet with MQTT.
Ethernet with Modbus TCP/IP (PLC = Slave).
Ethernet with Modbus TCP/IP (PLC = Master).
Ethernet test in Arduino or ESP32 PLC

RS485

RS-485 also known as TIA-485(-A) and EIA-485, is a standard defining the electrical characteristics of drivers and receivers for use in serial communications systems. Electrical signaling is balanced, and multipoint systems are supported. 

Our ESP32 Based PLCs incorporate the integrated circuit MAX485.

MAX485 is a low-power and slew-rate-limited transceiver used for RS-485 communication. It works at a single +5V power supply and the rated current is 300 μA. Adopting half-duplex communication to implement the function of converting TTL level into RS-485 level, it can achieve a maximum transmission rate of 2.5Mbps. MAX485 transceiver draws a supply current between 120μA and 500μA, on unloaded or fully loaded conditions, respectively, when the driver is disabled.  

The ESP32 based PLCs only support half duplex RS-485 communications.

To know more about RS485...

Hardware 

Important: Make sure that your ESP32 PLC is properly powered (12-24Vdc).

Switch configuration

For the RS-485 communication protocol there is one switch affecting this communication, the A zone left under switch:

RS85 Switch


Switch number 3 is used to select between Serial1 or RS485. In order to activate the R485 communication the switch 3 must be set to OFF.

Software

Important: Make sure you have the industrialshields-esp-3 board package properly installed in your Arduino IDE.

Once the hardware configuration is done, it's possible to proceed with the software configuration and also its usage. First of all, it is necessary to include the RS485.h library provided in our boards package.

#include <RS485.h>

Then don’t forget to implement the proper initialization of your communication on the setup() function. To test the connection we will use the serial, so we will initialize it too:

RS485.begin(38400);
Serial.begin(9600);

Note: Check that the velocity of transmission (baud rate) between the PLC and the Laptop (Serial) and between the PLC and the device connected by RS-485 properly set (the 2 devices communicating must work at the same speed).

Example Codes
Basic RS-485 write example (send):

// Include Industrial Shields libraries
#include <RS485.h>

//// IMPORTANT: check switches configuration

////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
// Begin serial port
Serial.begin(9600);

// Begin RS485 port
RS485.begin(38400);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
// Wait bytes in the serial port
if (Serial.available()) {
byte tx = Serial.read();

// Echo the byte to the serial port again
Serial.write(tx);

// And send it to the RS-485 port
RS485.write(tx);
}
}

Basic RS-485 read example (receive):

// Include Industrial Shields libraries
#include <RS485.h>

void setup() {
// Begin serial port
Serial.begin(9600);

// Begin RS485 port
RS485.begin(38400);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
// Print received byte when available
if (RS485.available()) {
byte rx = RS485.read();

// Hexadecimal representation
Serial.print("HEX: ");
Serial.print(rx, HEX);

// Decimal representation
Serial.print(", DEC: ");
Serial.println(rx, DEC);
}
}

Serial TTL

Communication Interface between two devices with a low level voltage. A Serial port sends data using a bit sequence. Two signals are used: Tx (Transmit Data) and Rx (Receive Data), which allow full-duplex communication.

ESP32 PLCs have two TTL ports, Serial 1 (RX0/TX0) and Serial 2 (RX1/TX1). Additionally there is the serial port used in the USB.

To know more about Serial TTL...

Hardware

Important: Make sure that your ESP32 PLC is properly powered (12-24Vdc).

Switch configuration

For the Serial protocol there is one switch affecting this communication, the A zone left under switch:

Serial Switch

To activate Serial 1: switch 3 must be set to ON.

To activate Serial 2: switch 2 must be set to ON and switch 4 must be set to OFF.

Software

Important: Make sure you have the industrialshields-esp-3 board package properly installed in your Arduino IDE.

Once the hardware configuration is done, it's possible to proceed with the software configuration and also its usage. In order to use the serial port we need to initialize the one we want to use:

Serial.begin(9600); // USB serial port
Serial1.begin(9600); // Serial 1
Serial2.begin(9600); // Serial 2

Basic Serial TTL read and write example.

This basic example uses the Serial (USB port) and Serial1 (TX1/RX1) to read and write one byte at a time.

void setup() {
// Initialize serial connections
Serial.begin(9600);
Serial1.begin(9600);
}

void loop() {
// Read byte from Serial and send it through Serial 1
if (Serial.available()) { // Check if there is available byte to read
Serial1.print(Serial.read());
}

// Read byte from Serial 1 and send it through Serial
if (Serial1.available()) {
Serial.print(Serial1.read());
}
}

I2C

I2C is a synchronous protocol which uses 2 cables, one for the clock (SCL) and one for the data (SDA). This means that the master and the slave send data through the same cable, which is controlled by the master, who also creates the clock signal. I2C does not use slave selection, but addressing.

I2C is a serial communications protocol. The speed is 100 Kbit/s in standard mode, but it allows speeds of up to 3.4 Mbit/s. It is a very used bus in the industry, mainly to communicate microcontrollers and their peripherals in integrated systems. It is also used to communicate integrated circuits among themselves, normally residing in a same PCB (printed circuit board).

Hardware

Important: Make sure that your ESP32 PLC is properly powered (12-24Vdc).

The I2C communication works at 5V and does not require pull-up resistors, since they are already implemented in the PCB.

Switch configuration

For the I2C communication there is no configuration needed, it is always enabled. There is not any switch that affects it.

Used pins

The pins used in the I2c communication are the following:

ESP32 PLC Pinout
ESP32 Pin
SDA
21
SCL
22

Software

Important: Make sure you have the industrialshields-esp-3 board package properly installed in your Arduino IDE.

The necessary functions to use the I2C are implemented in the Wire.h library.

Example code

This simple example implements an I2C scanner, which scans the I2C-bus for devices. If a device is found, it is reported to the Arduino serial monitor.

#include <Wire.h>

void setup()
{
Wire.begin();
//Wire.setTimeout(10000);
//Wire.setClock(100000);
Serial.begin(9600);
while (!Serial);
Serial.println("\nI2C Scanner");
}

void loop()
{
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 0x01; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // wait 5 seconds for next scan
}

To know more about I2C communication...

I2C Bus on PLC for industrial automation

How to setup external i2c on industrial Arduino or ESP32 based PLC

SPI

The  Serial Peripheral Interface (SPI) is a synchronous serial communication interface specification used for short-distance communication, primarily in embedded systems. SPI devices communicate in full duplex mode using a master-slave architecture, usually with a single master.

SPI uses 3 pins (SCLK, MOSI, MISO) to communicate, and one additional chip selector (also called SS, slave select) pin, used by the master to signal the slave it wants to communicate to:

Hardware

Important: Make sure that your ESP32 PLC is properly powered (12-24Vdc).

The SPI communication works at 5V.

The SPI pins are not stablished with a pull-up or a pull-down configuration. The state of these pins is unknown, so when they are used they require a pull-up or a pull-down configuration. The ESP32 board allows the pins to be set in a pull-up configuration by software. Alternatively, if the internal pull-up isn't configured, an external pull-up or pull-down must be used in order for the pins to work correctly.

Switch configuration

For the SPI communication there is no configuration needed, there is not any switch that affects it.

Used pins

The pins used in the SPI communication are the following:

Function
PLC Pin
ESP32 Pin
MISO
SO
GPIO 19
MOSI
SI
GPIO 23
CLOCK
SCK
GPIO 18

These pins can only work as 5V SPI pins if the Ethernet protocol is not going to be used, since the Ethernet protocol already uses the SPI to communicate with the ESP32 board. Therefore, SPI cannot be used at the same time that the Ethernet communication.

Additionally, chip select pins might be used.

Software

Important: Make sure you have the industrialshields-esp-3 board package properly installed in your Arduino IDE.

Our SPI communication library is based on the Arduino SPI library, which allows SPI communication using ESP32 based PLCs acting as the master only.

Example program: SPI master

This program shows how to set up the ESP32 as a master in SPI communication, and send and receive data. In this case the character "0" is sent, and the received data is stored in the corresponding variable (SPI transfer is based on a simultaneous send and receive) and printed through the serial port.

// Include the SPI library:
#include <SPI.h>

// Set pin as the slave select:
const int slaveSelectPin = GPIO_0;
volatile byte receivedData;

void setup() {
Serial.begin(9600);
// Set the slaveSelectPin as an output:
pinMode(slaveSelectPin, OUTPUT);
// Initialize SPI:
SPI.begin();
}

void loop() {

SPI.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE0));
digitalWrite(slaveSelectPin, LOW); // Start of transmission: set chip select LOW
receivedData = SPI.transfer('0');
digitalWrite(slaveSelectPin, HIGH); // End of transmission: set chip select HIGH
SPI.endTransaction();

Serial.println(char(receivedData));

delay(100);
}

To know more about SPI communication...

SPI Bus on Industrial Shields PLC

Wi-Fi

Wi-Fi is one of the most important technological developments of the modern age. Similar to other wireless connection types, like Bluetooth, it's a radio transmission technology built upon a set of standards to allow high-speed and secure communications between a wide variety of digital devices, access points and hardware. It makes it possible for Wi-Fi capable devices to access the internet without the need for wires. It can operate over short and long distances, be locked down and secured, or open and free. It's incredibly versatile and easy to use.

Our ESP32 based PLCs support both 2.4GHz and 5GHz connections. 2.4GHz thanks to the internal ESP32, and 5GHz due to a dedicated chip, the ISM43340, which is integrated in the PLC.

Hardware

Important: Make sure that your ESP32 PLC is properly powered (12-24Vdc).

Switch configuration

There is not any necessary configuration to use the Wi-Fi capabilities.

Software

Important: Make sure you have the industrialshields-esp-3 board package properly installed in your Arduino IDE.

In order to use the Wi-Fi communications the correct library needs to be included in the program code, depending on the type of network you want to use:

-2.4GHz. WiFi.h

-5GHz: WiFi5.h

These libraries can be included in the the code this way:

#include <WiFi.h>
#include <WiFi5.h>

Example code

This simple program scans the WiFi searching for available network and prints the results thrugh the serial.

#include "WiFi.h"

void setup()
{
Serial.begin(115200);

// Set WiFi to station mode and disconnect from an AP if it was previously connected
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);

Serial.println("Setup done");
}

void loop()
{
Serial.println("scan start");

// WiFi.scanNetworks will return the number of networks found
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n == 0) {
Serial.println("no networks found");
} else {
Serial.print(n);
Serial.println(" networks found");
for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(")");
Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*");
delay(10);
}
}
Serial.println("");

// Wait a bit before scanning again
delay(5000);
}

More Wi-Fi examples with code:

How to connect your ESP32 based PLC to Wi-Fi

ESP32 Bluetooth / BLE / WiFi

How to work with the 5GHz Wi-Fi module of the ESP32

How to program the 10 I/Os ESP32 industrial PLC via WiFi

Bluetooth

Bluetooth is a wireless technology standard. It was developed as a way to exchange data over a short range. It operates in the 2400-2483.5 MHz range within the ISM 2.4 GHz frequency band. Data is split into packets and exchanged through one of the 79 designed Bluetooth channels (each of which with a 1 MHz bandwidth).  

Hardware

Important: Make sure that your ESP32 PLC is properly powered (12-24Vdc). The USB is not capable of properly powering the PLC and the Ethernet communication. There is not any switch or additional configuration needed for the Bluetooth communication to work.

Software 

Important: Make sure you have the industrialshields-esp-3 board package properly installed in your Arduino IDE.

This example shows how to read bytes and send bytes through Bluetooth using BluetootSerial. The Serial port is used to send and receive data from the PC. To communicate with the PLC through Bluetooth a mobile app like "Serial Bluetooth Terminal" can be used. To do so, establish the Bluetooth connection with the PLC and select the device on the app.

#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

void setup() {
Serial.begin(115200);
SerialBT.begin("ESP32test"); //Bluetooth device name
Serial.println("The device started, now you can pair it with bluetooth!");
}

void loop() {
if (Serial.available()) {
SerialBT.write(Serial.read());
}
if (SerialBT.available()) {
Serial.write(SerialBT.read());
}
delay(20);
}

More Bluetooth usage examples:

Interact with M-Duino WiFi/BLE industrial PLC via Bluetooth
How to control an ESP32 industrial controller via Bluetooth

Special functions

RTC

The term Real-Time Clock is used to avoid confusion with ordinary hardware clocks which are only signals that govern digital electronics, and do not count time using human units. RTC should not be confused with real-time computing, which shares the acronym but does not directly relate to time of day.

Although keeping time can be done without an RTC, using one has benefits:

  • Low power consumption (important when running from alternate power.
  • Frees the main control system for time-critical tasks.
  • Sometimes more accurate than other methods.

There is a 3,3V lithium coin cell battery supplying the RTC. RTC Module is based on the DS1307 Chip. The DS1307 serial real-time clock (RTC) is a lowpower, full binary-coded decimal (BCD) clock/calendar plus 56 bytes of NV SRAM. Address and data are transferred serially through an I2C, bidirectional bus.

The clock/calendar provides seconds, minutes, hours, day, date, month, and year information. The end of the month date is automatically adjusted for months with fewer than 31 days, including corrections for leap year. The clock operates in either the 24-hour or 12-hour format with AM/PM indicator. The DS1307 has a built-in power-sense circuit that detects power failures and automatically switches to the backup supply. Timekeeping operation continues while the part operates from the backup supply.

Hardware Configuration

Important: Make sure that your ESP32 PLC is properly powered (12-24Vdc).

Switch configuration:

In ESP32 based PLCs, I2C is always enabled, so there is no configuration needed to use the RTC.

Software Configuration

Important: Make sure you have the industrialshields-esp-3 board package properly installed in your Arduino IDE.

In order to use the RTC, the RTC.h library will be used, so it is necessary to include it in our code.This library is provided our boards package. It can be included like this:

#include <RTC2.h>

To check if the RTC port is working it is easy to use the serial monitor from the Arduino IDE using the right sentence inside the setup() function:

Serial.begin(9600L);

Example Code  

Basic RTC Test

// RTC library example
// by Industrial Shields
#include <RTC2.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(9600L);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  if (!RTC.read()) {
    Serial.println("Read date error: is time set?");
    }
     else {
    Serial.print("Time: ");
    Serial.print(RTC.getYear());
    Serial.print("-");
    Serial.print(RTC.getMonth());
    Serial.print("-");
    Serial.print(RTC.getMonthDay());
    Serial.print(" ");
    Serial.print(RTC.getHour());
    Serial.print(":");
    Serial.print(RTC.getMinute());
    Serial.print(":");
    Serial.print(RTC.getSecond());
    Serial.print(" (");
    Serial.print(RTC.getTime());
    Serial.println(")");
  }
  delay(1000);
}

SD

Secure Digital (SD)is a non-volatile memory card format developed by the SD Card Association (SDA) for use in portable devices.

The newer families of SD card improve card speed by increasing the bus rate (the frequency of the clock signal that strobes information into and out of the card).

Whatever the bus rate, the card can signal to the host that it is "busy" until a read or a write operation is complete. Compliance with a higher speed rating is a guarantee that the card limits its use of the "busy" indication. Size: 15 x 11 x 1 mm.

The SD capabilities are the following:

  • Maximum capacity: 4GB. Higher capacity cards are usable, but only the first 4GB will be accessible.
  • Allowed file system architectures: FAT32 & FAT16.

Hardware Configuration

Make sure that your ESP32 PLC is properly powered (12-24Vdc).

Switch configuration

The microSD uses the SPI communication to interact with the ESP32. The SPI protocol is always
enabled, as there are no switches that configure it, so there is not any necessary configuration to use the microSD.

Software Configuration

Important: Make sure you have the industrialshields-esp-3 board package properly installed in your Arduino IDE.

Using the boards of Industrial Shields, there is a library that simplifies the uSD implementation called SD, based on the Arduino SD library implementation with some minor changes, such as setting the chip select pin used in the SPI communication with the SD module.

Example Code

This example code initializes the SD card and prints the contents of it root directory through the serial port.

#include <SD.h>

const int chipSelect = 13;
File root;

void setup() {
 // Open serial communications and wait for port to open:
  Serial.begin(115200);
  // wait for Serial Monitor to connect. Needed for native USB port boards only:
  while (!Serial);

pinMode(13, OUTPUT);
  Serial.print("Initializing SD card...");

  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("1. is a card inserted?");
    Serial.println("2. is your wiring correct?");
    Serial.println("3. did you change the chipSelect pin to match your shield or module?");
    Serial.println("Note: press reset or reopen this serial monitor after fixing your issue!");
    while (true);
  }

  Serial.println("initialization done.");

  root = SD.open("/");

  printDirectory(root, 0);

  Serial.println("done!");
}

void loop() {
  // nothing happens after setup finishes.
}

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

To know more about SD cards:

Basics with SD card in an industrial PLC

GPIO

3.3Vdc/5Vdc Signals

3.3V Pins

These pins can be programmed according to ESP features such as I/Os operating at 3.3V or any additional features present in the pins:

PLC Terminal
ESP32 Pin
TX1
  GPIO 17
RX1
  GPIO 16
VN
SENS VN (GPIO 39)
VP
SENS VP (GPIO 36)
SO
GPIO 19
SI
GPIO 23
SCK
GPIO 18

Serial 1 – RX1/TX1:
The Serial1 protocol can also work as a 3.3V pin.

Vp/Vn:
These pins can work as 3.3V input only.

SPI – MISO/MOSI/SCK:
These pins can also work as 3.3V pins, though only if the Ethernet protocol is not going to be used. As the Ethernet protocol uses the SPI to communicate with the ESP board, both the Ethernet connection and the pins cannot be used at the same time.

Warning: in order to use the Serial pins as GPIO, the corresponding switches must be set up so the Serial 1 is selected (check the Hardware section for more details).

5V Pins

These pins can be programmed according to ESP features such as I/Os operating at 5V or any additional features present in the pins:

PLC Terminal
ESP32 Pin
SCL
GPIO 22
SDA
GPIO 21
GPIO 0
GPIO 0

I2C Pins – SDA/SCL:
The I2C protocol is meant to work in a pull-up configuration, which are included in the board. Therefore, they can only be used in pull-up configuration: it reads 5V when nothing is connected.

GPIO 0:
The GPIO_0 pin works at 5Vdc, and can be used as a digital input or output.

ESP32 Dual Core

The ESP32 programmable logic controller include 2 Xtensa 32-bit LX6 microprocessors. When we run code on Arduino IDE, by default, it runs on core 1, as we can check with this simple program:

void setup() {
Serial.begin(115200);
Serial.print("setup() running on core ");
Serial.println(xPortGetCoreID());
}

void loop() {
Serial.print("loop() running on core ");
Serial.println(xPortGetCoreID());
}

However, we can also use the second core, for better performance and efficiency. In order to work with the second core, we just need to define a second loop function, called "loop1()". The code inside this function will be executed by core 0, whereas the code inside the usual "loop()" function is executed by core 1. This way we can define different tasks for each core:

void setup() {
  // Setup code
}
void loop() {
  // Core 1 tasks
}
void loop1() {
  // Core 0 tasks
}

Organizing the program like this we can take advantage of the 2 cores in the ESP32. Some considerations need to be made when using the dual core, though, as concurrency problems may appear: for example if both try to use the Serial at the same time. In order to avoid this problems mechanisms such as sempahores might be used.

To know more about the ESP32 dual core:

How to use the ESP32 industrial PLC Dual Core

FreeRTOS

FreeRTOS is a popular open-source real-time operating system (RTOS) designed for microcontrollers and small embedded systems. It provides a lightweight, scalable, and portable operating system kernel, along with a range of software components and tools to support the development of embedded applications. FreeRTOS can be used with the Arduino IDE on ESP32 boards to add real-time operating system functionality to your projects.

With FreeRTOS, you can create multiple tasks in your sketch, each with its own priority, and use synchronization mechanisms like semaphores and mutual exclusion to coordinate the tasks. This can be useful for real-time applications that require precise timing and coordination of tasks.

There is no need to include any library to use FreeRTOS with ESP32 based PLCs, since it is integrated into ESP-IDF as a component (Arduino leverages ESP-IDF).

One of the most useful features of FreeRTOS are tasks, schedulables pieces of code. In order to create a task the function xTaskCreate() is used.

Example code:

This program creates 2 tasks to periodically set HIGH and LOW two digital outputs. The LEDs on the PLC

TaskHandle_t Task1;
TaskHandle_t Task2;

void setup() {
Serial.begin(115200);
pinMode(Q0_0,OUTPUT);
pinMode(Q0_1,OUTPUT);

xTaskCreate(Task1code,"Task1",10000,NULL,1,&Task1);
delay(500);

xTaskCreate(Task2code,"Task2",10000,NULL,1,&Task2);
delay(500);
}

void Task1code( void * parameter ){
Serial.print("Task1 is running on core ");
Serial.println(xPortGetCoreID());

for(;;){
digitalWrite(Q0_0, HIGH);
delay(500);
digitalWrite(Q0_0, LOW);
delay(500);
}
}

void Task2code( void * parameter ){
Serial.print("Task2 is running on core ");
Serial.println(xPortGetCoreID());

for(;;){
digitalWrite(Q0_1, HIGH);
delay(1000);
digitalWrite(Q0_1, LOW);
delay(1000);
}
}

void loop() {}