I2C
I2C is widely used to connect devices such as sensors, ADCs, RTCs, and DACs. The I2C of ESP32 supports arbitrary mapping. When pins are occupied, I2C can be mapped to other pins to resolve pin conflicts.
Notes:
- Pull-up resistors are required on the SDA and SCL lines.
- Some ESP32s support multi-channel I2C. For information on whether mapping is supported, please refer to the peripheral pin assignment chapter in the corresponding chip manual.
Comprehensive Example 1 - Remap Multiple Groups of I2C
Map I2C pins to GPIO3 and GPIO4 through code
#include <Wire.h>
#include "DFRobot_SHTC3.h"
// Define two groups of I2C pins
#define SDA1 3
#define SCL1 4
#define SDA2 5
#define SCL2 6
// Create two I2C instances
TwoWire I2CBus1 = TwoWire(0);
TwoWire I2CBus2 = TwoWire(1);
DFRobot_SHTC3 SHTC3(&I2CBus2);
void setup() {
Serial.begin(115200);
delay(1000);
// Initialize two I2C buses
I2CBus1.begin(SDA1, SCL1);
I2CBus2.setPins(SDA1, SCL1);
// I2CBus2.begin(SDA2, SCL2); // Since SHTC3.begin will call I2CBus2.begin, it is only necessary to set the pins
SHTC3.begin();
}
void loop() {
delay(2000);
}
UART
ESP32 has multiple UART ports, and UART can be mapped to other pins.
Note: Some ESP32s support multiple UARTs. For information on whether mapping is supported, please refer to the peripheral pin assignment chapter in the corresponding chip manual.
ESP32 Chip UART Resource Table
begin
Serial0.begin(uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin);
Serial1.begin(uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin);
Serial2.begin(uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin);
Function: Initialize UART0, UART1, UART2
Parameters:
- baudrate: Baud rate
- config: Data bits, parity bit, stop bit
- SERIAL_8N1: 8 data bits, no parity bit, 1 stop bit
- SERIAL_8O1: 8 data bits, with parity bit, 1 stop bit
- Other types are similar to the above parameters
- rxPin: RX pin
- txPin: TX pin
Return value: true or false
Comprehensive Example 1 - Remap Multiple Groups of UART
void setup() {
Serial0.begin(9600, SERIAL_8N1, /*rx =*/3, /*tx =*/4);
Serial1.begin(115200, SERIAL_8O1, /*rx =*/5, /*tx =*/6);
Serial2.begin(115200, SERIAL_8N1, /*rx =*/7, /*tx =*/8);
}
void loop() {
}
SPI
The SPI of ESP32 supports arbitrary mapping. When pins are occupied, SPI can be mapped to other pins to resolve pin conflicts.
Note: Some ESP32s support multiple SPIs. For information on whether mapping is supported, please refer to the peripheral pin assignment chapter in the corresponding chip manual.
begin
SPI.begin(sck, miso, mosi, cs);
Function: Initialize SPI with default configuration and specify sck, miso, mosi, cs pins
Parameters: Corresponding pin numbers
Return value: true or false
Comprehensive Example 1 - Remap Multiple Groups of SPI Pins
#include <SPI.h>
// VSPI pin definition (Device A)
#define VSPI_MISO 19
#define VSPI_MOSI 23
#define VSPI_SCLK 18
#define VSPI_SS 5
// HSPI pin definition (Device B)
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define HSPI_SCLK 14
#define HSPI_SS 15
// Create two SPI objects (note that the default SPI cannot be used)
SPIClass vspi(VSPI);
SPIClass hspi(HSPI);
void setup() {
Serial.begin(115200);
delay(1000);
// Initialize VSPI
vspi.begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS);
pinMode(VSPI_SS, OUTPUT);
digitalWrite(VSPI_SS, HIGH);
// Initialize HSPI
hspi.begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_SS);
pinMode(HSPI_SS, OUTPUT);
digitalWrite(HSPI_SS, HIGH);
}
void loop() {
delay(1000);
}
SD Library
The SD library enables ESP32 to drive an SD card, thereby providing ESP32 with larger storage space for storing various types of data such as images, audio, videos, etc.
Note: The SD library is used for overall operations on files and folders. If you need to operate on the contents of files, you need to use the FS library.
begin
bool begin(
uint8_t ssPin = SS, SPIClass &spi = SPI, uint32_t frequency = 4000000, const char *mountpoint = "/sd", uint8_t max_files = 5, bool format_if_empty = false
);
Function: Initialize SD with default configuration
Parameters:
- ssPin: SD card chip select pin (The default pin corresponding to SS can be found in the pins_arduino.h file of the development board in the variants folder)
- spi: Use the specified SPI for communication (using the default SPI port)
Return value: true or false
Example:
#include "SD.h"
#include "SPI.h"
void setup() {
// Initialization method 1 - Initialize with all default values
SD.begin();
// Initialization method 2 - Initialize by specifying the SD card chip select pin
// SD.begin(/*SDCS =*/10); // The chip select pin of SD is GPIO10
// Initialization method 3 - Initialize by specifying SPI pins and chip select pin
// SPI.begin(/*sck =*/4, /*miso =*/5, /*mosi =*/6, /*cs =*/10);
// SD.begin(/*SDCS =*/10); // The chip select pin of SD is GPIO10
// Initialization method 4 - Initialize by specifying other SPI ports
// SPI1.begin(/*sck =*/4, /*miso =*/5, /*mosi =*/6, /*cs =*/10);
// SD.begin(/*SDCS =*/10, SP1); // The communication port of SD is SPI1, and the chip select pin is GPIO10
}
void loop() {
}
exists
bool exists (const char *filepath);
Function: Check if a file or folder exists on the SD card
Parameters:
- filepath: The path of the file or directory to check
Return value: true indicates the file or folder exists, false indicates it does not exist
open
File open(const char *filepath, uint8_t mode = FILE_READ);
Function: Open a file on the SD card. If the file does not exist and is opened in write mode, a file with the specified name will be created. (The所在路径 must exist in advance)
Parameters:
- filepath: The path of the file or directory to check
- mode: Opening mode
- FILE_READ: Read-only mode
- FILE_WRITE: Write mode (If the file exists, it will overwrite the file; if the file does not exist, it will create the file)
- FILE_APPEND: Append mode (If the file exists, it will add content to the end of the file; if the file does not exist, it will create the file)
Return value: Returns a 'File' object on success, representing the opened file or directory; returns an invalid 'File' object on failure
remove
bool remove(const char *filepath);
Function: Remove a file.
Return value: true or false
mkdir
bool mkdir(const char *filepath);
Function: Create a folder
Parameters:
- filepath: The path of the file or directory to be created
Return value: true or false
rmdir
bool rmdir(const char *filepath);
Function: Remove a folder (The folder to be removed must be empty)
Parameters:
- filepath: The path of the file or directory to be removed
Return value: true or false
FS Library
ESP32 can perform a series of operations such as reading and writing files through the FS library.
close
void close();
Function: Save data, close the file, and release resources
Read and Write Operations
read
int read(); //Method 1
int read(uint8_t *buf, size_t size); //Method 2
Function: Read data from the file
Parameters:
- buf: Data buffer
- size: Number of bytes to read
Return value: Method 1 returns byte data (0-255), Method 2 returns the actual number of bytes read
write
size_t write(uint8_t data); //Method 1
size_t write(const uint8_t *buf, size_t size); //Method 2
Function: Write data to the file
Parameters:
- data: The byte to be written
- buf: Data buffer
- size: Number of bytes to read
Return value: Returns the actual number of bytes written
print / println
size_t print();
size_t println();
Function: Write data to the file (print and println support writing various types of data)
Parameters:
- Including strings, characters, integers, floating-point numbers, etc.
Return value: Returns the actual number of bytes written
Other Operations
flush
void flush();
Function: Immediately write the data in the buffer to the storage device
Example:
File myFile = SD.open("/example.txt", FILE_WRITE);
if (myFile) {
myFile.println("Hello, SD!");
myFile.flush(); // Write the data in the buffer to the SD card
myFile.close();
}
size
size_t size();
Function: Get the number of bytes of the file
available
int available();
Function: Get the number of unread bytes (Affected by the file pointer)
position
int peek();
Function: Return the current file pointer position
peek
int peek();
Function: View the next byte to be read
seek
int peek();
Function: Move the file pointer to the specified position
Comprehensive Example 1 - Read and Write SD Card Files
#include "FS.h"
#include "SD.h"
#include "SPI.h"
//List directory
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.path(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
//Create directory
void createDir(fs::FS &fs, const char * path){
Serial.printf("Creating Dir: %s\n", path);
if(fs.mkdir(path)){
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
//Remove directory
void removeDir(fs::FS &fs, const char * path){
Serial.printf("Removing Dir: %s\n", path);
if(fs.rmdir(path)){
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
//Read file and print to serial port
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while(file.available()){
Serial.write(file.read());
}
file.close();
}
//Write data to file
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
//Append data to file
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
//Rename file
void renameFile(fs::FS &fs, const char * path1, const char * path2){
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
//Delete file
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\n", path);
if(fs.remove(path)){
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
//Get the time required to read file content
void testFileIO(fs::FS &fs, const char * path){
File file = fs.open(path);
static uint8_t buf[512];
size_t len = 0;
uint32_t start = millis();
uint32_t end = start;
if(file){
len = file.size();
size_t flen = len;
start = millis();
while(len){
size_t toRead = len;
if(toRead > 512){
toRead = 512;
}
file.read(buf, toRead);
len -= toRead;
}
end = millis() - start;
Serial.printf("%u bytes read for %u ms\n", flen, end);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
size_t i;
start = millis();
for(i=0; i<2048; i++){
file.write(buf, 512);
}
end = millis() - start;
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
file.close();
}
void setup(){
Serial.begin(115200);
if(!SD.begin()){
Serial.println("Card Mount Failed");
return;
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
listDir(SD, "/", 0);
createDir(SD, "/mydir");
listDir(SD, "/", 0);
removeDir(SD, "/mydir");
listDir(SD, "/", 2);
writeFile(SD, "/hello.txt", "Hello ");
appendFile(SD, "/hello.txt", "World!\n");
readFile(SD, "/hello.txt");
deleteFile(SD, "/foo.txt");
renameFile(SD, "/hello.txt", "/foo.txt");
readFile(SD, "/foo.txt");
testFileIO(SD, "/test.txt");
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}
void loop(){
}
I2S
I2S enables ESP32 to connect to digital audio devices for sound collection and output.
Initialization Related
begin
bool begin(i2s_mode_t mode, uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch, int8_t slot_mask=-1);
Function: Initialize I2C with default configuration
Parameters:
- mode: I2S working mode
- I2S_MODE_STD: Standard mode (only left and right channels)
- I2S_MODE_TDM: Time-division multiplexing mode (variable number of channels)
- I2S_MODE_PDM_TX: PDM transmission mode, which can convert PCM data format to PDM data format and output, only requiring CLK and DOUT pins (only supporting I2S0, 16-bit width sampling data)
- I2S_MODE_PDM_RX: PDM reception mode, which can receive PDM data format and convert it to PCM data format, only requiring CLK and DIN pins (only supporting I2S0, 16-bit width sampling data)
- rate: Sampling rate, the number of samples collected per second, in Hz
- bits_cfg: Data bit width
- I2S_DATA_BIT_WIDTH_8BIT
- I2S_DATA_BIT_WIDTH_16BIT
- I2S_DATA_BIT_WIDTH_24BIT
- I2S_DATA_BIT_WIDTH_32BIT
- ch: Channel
- I2S_SLOT_MODE_MONO: Mono (all channel data are the same)
- I2S_SLOT_MODE_STEREO: Stereo (different channel data are different)
- slot_mask: Channel mask, default is -1
Return value: true or false
setPins
void setPins(int8_t bclk, int8_t ws, int8_t dout, int8_t din=-1, int8_t mclk=-1);
Function: Set I2S pin interfaces in I2S_MODE_STD and I2S_MODE_TDM modes
Parameters:
- bclk: Bit clock pin
- ws: Word select pin
- dout: Data output pin (can be set to -1 if not used)
- din: Data input pin (can be set to -1 if not used)
- mclk: Master clock pin (can be set to -1 if not used)
setPinsPdmTx
void setPinsPdmTx(int8_t clk, int8_t dout0, int8_t dout1=-1);
Function: Set I2S pin interfaces in I2S_MODE_PDM_TX mode
Parameters:
- clk: Bit clock pin
- dout0: Data output pin 0
- dout1: Data output pin 1 (can be set to -1 if not used)
setPinsPdmRx
void setPinsPdmRx(int8_t clk, int8_t din0, int8_t din1=-1, int8_t din2=-1, int8_t din3=-1);
Function: Set I2S pin interfaces in I2S_MODE_PDM_RX mode
Parameters:
- clk: Bit clock pin
- din0: Data input pin 0
- din1: Data input pin 1 (can be set to -1 if not used)
- din2: Data input pin 2 (can be set to -1 if not used)
- din3: Data input pin 3 (can be set to -1 if not used)
recordWAV
uint8_t * recordWAV(size_t rec_seconds, size_t * out_size);
Function: Record a short WAV audio to memory
Parameters:
- rec_seconds: The number of seconds to record
- out_size: Returns the size of the buffer in bytes
Return value: Returns a pointer to the buffer containing the recorded WAV data; returns NULL if an error occurs
playWAV
void playWAV(uint8_t * data, size_t len);
Function: Play WAV audio from memory
Parameters:
- data: Data buffer
- len: Size of the buffer in bytes
playMP3
bool playMP3(uint8_t *src, size_t src_len);
Function: Play MP3 audio from memory
Parameters:
- src: Data buffer
- src_len: Size of the buffer in bytes
Return value: true or false