Working with Arduino
This chapter includes the following sections. Please read as needed:
Arduino Getting Started
New to Arduino ESP32 development and looking for a quick start? We have prepared a comprehensive Getting Started Tutorial for you.
- Section 0: Getting to Know ESP32
- Section 1: Installing and Configuring Arduino IDE
- Section 2: Arduino Basics
- Section 3: Digital Output/Input
- Section 4: Analog Input
- Section 5: Pulse Width Modulation (PWM)
- Section 6: Serial Communication (UART)
- Section 7: I2C Communication
- Section 8: SPI Communication
- Section 9: Wi-Fi Basics
- Section 10: Web Server
- Section 11: Bluetooth
- Section 12: LVGL GUI Development
- Section 13: Comprehensive Project
Note: This tutorial uses the ESP32-S3-Zero as a reference example, and all hardware code is based on its pinout. Before you start, we recommend checking the pinout of your development board to ensure the pin configuration is correct.
Set Up the Development Environment
Install and Configure the Arduino IDE
Use Arduino IDE 2.x and install esp32 by Espressif Systems 3.3.11. For the installation process, see the Arduino IDE Installation and Configuration Tutorial.
Add the Espressif official index to the Additional Boards Manager URLs under "File" > "Preferences", then select the above version in the Boards Manager:
https://espressif.github.io/arduino-esp32/package_esp32_index.json
Install Libraries and Select the Screen
Obtain the complete project from ESP32-S3-LR1121-ePaper-2.9 example package.
| Library | Version | Installation Method |
|---|---|---|
| RadioLib | 7.7.1 | Install via the Arduino Library Manager; the repository also includes the corresponding library |
| Waveshare LR1121 E-Paper | 0.1.0, use the copy included with the current project | Copy examples/arduino/libraries/Waveshare_LR1121_EPaper to the libraries directory of the Sketchbook |
| SPI, Wire, WiFi, Preferences, SD_MMC | Provided with Arduino-ESP32 3.3.11 | Do not install separately |
Restart the Arduino IDE after copying is complete. If libraries with the same name already exist, back them up and remove the old copies first, and confirm that the compilation log uses the current library path. This set of Arduino examples uses the native display driver and does not depend on GxEPD2, Adafruit_GFX, LVGL, or the ESP Board Manager.
Edit src/WaveshareConfig.h in the library and enable only the 2.9-inch configuration:
//#define WAVESHARE_EPAPER_213
#define WAVESHARE_EPAPER_290
Project Parameter Settings
Set the following in the "Tools" menu:
| Option | Setting |
|---|---|
| Board | ESP32S3 Dev Module |
| USB CDC On Boot | Enabled |
| USB Mode | Hardware CDC and JTAG |
| Flash Size | 16MB (128Mb) |
| PSRAM | OPI PSRAM |
| Partition Scheme | Default scheme; after adding features in example 09, the application space needs to be rechecked |
| Port | The actual port of the development board |
Build and Upload
- Connect the development board with a Type-C cable that supports data transfer.
- Open the
.inofile with the same name as the directory, for exampleexamples/arduino/03_epaper/03_epaper.ino. - Confirm the board parameters and port, and click "Verify" to compile.
- After compilation succeeds, click "Upload". If connection fails, follow the Download Mode Instructions.
- Open the serial monitor, select the 115200 baud rate, and check the log and behavior of the corresponding example.
The following describes the operation steps and expected source code behavior for each example. The actual running results need to be verified against the corresponding logs and hardware behavior.
Example
Each directory is an independent program. After switching examples, recompile and upload; before transmitting with the wireless examples, complete the Antenna and Wireless Parameter Check.
| Directory | Function | Additional Conditions |
|---|---|---|
| 01_ws2812_led | RGB LED color changes | None |
| 02_i2c_scan | Scan onboard I2C devices | None |
| 03_epaper | Black-and-white display and refresh count | 2.9-inch configuration |
| 04_bat_axp2602 | Battery information reading | Matching battery and correct sampling configuration |
| 05_rtc_pcf85063 | Time reading | Set a valid time as needed |
| 06_lr1121_pingpong | LoRa point-to-point transmit/receive | Antenna, peer with the same parameters |
| 07_sd_card | Storage card read/write verification and e-paper status display | FAT32 card |
| 08_deep_sleep | Timed and button wake-up | Observe the wake-up log |
| 09_comprehensive_demo | Self-test, continuous load, and sleep | Antenna; TF card, STA, and LoRa peer prepared as needed |
| 10_lr1121_lorawan | LoRaWAN Class A OTAA | Gateway, server, and OTAA credentials |
| 11_LoRaWAN_ABP | LoRaWAN Class A ABP | Session parameters and counters matching |
| 12_LoRaWAN_Class_C | Class C asynchronous downlink | Server Class C configuration |
| 13_LoRaWAN_Multicast | Class C static multicast reception | Multicast configuration; multiple boards can check the one-to-many effect |
01_ws2812_led: RGB LED
Example Description
Uses GPIO21 to control 1 WS2812 in GRB format, with the color continuously changing between red, green, and blue, and the channel value limited to 48/255.
Operation Steps and Running Effect
Upload the example. The serial port should output WS2812: GPIO21, one GRB LED. Observe the color changes of the onboard LED. This example does not refresh the e-paper; the LED power is also controlled by the shared power supply of GPIO38.
02_i2c_scan: I2C Scan
Example Description
Scans I2C devices via GPIO13/SDA and GPIO14/SCL, outputting only serial logs.
Operation Steps and Running Effect
After uploading, check the addresses and device names in the serial port. The onboard RTC address is 0x51, and the AXP2602 address is 0x62. If scanning fails, check the power supply, bus levels, and pull-ups; an address response does not mean that all functions of the device have been verified.
03_epaper: E-Paper Display
Example Description
Displays landscape text and a refresh count. The first frame is a full refresh, after which the driver manages full-screen fast refreshes, inserting a full refresh after the limit is reached.
Operation Steps and Running Effect
Confirm that only WAVESHARE_EPAPER_290 is enabled, then upload. The serial port outputs the selected panel and visible dimensions, RAM dimensions, and BUSY=HIGH, and the screen displays EPAPER and an incrementing REFRESH count.
Chinese and other non-ASCII characters require separate font library adaptation.
04_bat_axp2602: Fuel Gauge
Example Description
Reads the battery voltage, signed current, SOC, chip temperature, and remaining time estimate through the AXP2602 driver in the repository library, and outputs them to the serial port and e-paper.
Operation Steps and Running Effect
Check the battery and sampling circuit according to the Battery Connection Instructions, then upload the example. Check whether consecutive samples change reasonably with the actual power supply state; do not treat an uncalibrated SOC or time estimate as a measured battery capacity value.
05_rtc_pcf85063: RTC Time
Example Description
Reads the PCF85063A time and the low-voltage flag. When the time is invalid, writes the example default time 2026-01-01 12:00:00; it does not automatically obtain the current time.
Operation Steps and Running Effect
If you need an actual date, first modify the initial time in the .ino and then upload. Check the date, time, and voltage_low on the serial port, and observe the time changes on the screen. An existing valid time will not be overwritten by the default value; if you need to set the time again, you should explicitly call rtc.set().
06_lr1121_pingpong: LoRa Point-to-Point
Example Description
The program periodically sends PING, replies with PONG after receiving a peer's PING, and outputs RSSI, SNR, and status codes.
Notes
The default parameters are provided by LR1121BoardRadio::begin() in WaveshareRadio.h: 868 MHz, 125 kHz, SF7, coding rate 4/5, 22 dBm. Adjust them first according to regional, hardware, and antenna limits; the default power cannot be directly used as the basis for permitted transmission.
Operation Steps and Running Effect
- Prepare two development boards and matching antennas, and confirm that the parameters on both sides are consistent.
- If you need to modify the parameters, explicitly pass them to
boardRadio.begin()in the .ino, keeping both ends consistent. - Upload them separately and open the serial ports, checking
LR1121 init: 0, PING/PONG, and the received RSSI and SNR.
An initialization return of 0 indicates that this RadioLib initialization succeeded; it does not replace the two-board transmit/receive test.
07_sd_card: Storage Card Read/Write
Example Description
Uses the SD_MMC built into Arduino-ESP32 to access the card in 1-bit mode via GPIO10/CMD, GPIO11/D0, and GPIO12/CLK.
The e-paper displays the card capacity, mount, read/write, and unmount status, and the title is updated from SD TEST to SD PASS or SD FAIL. After unmounting, refresh the final result, then let the screen sleep, stop SPI, and turn off the shared power supply; the result screen is still retained.
Operation Steps and Running Effect
- Power off, insert a FAT32 card, and confirm the Test File Impact.
- Upload the example, and check the card information, root directory listing, write and byte-by-byte read-back results in the serial port, as well as the various statuses on the screen.
- Check the final
SD PASS/SD FAILscreen and the serial portFINALresult.
The program does not format or overwrite existing test files. PASS means this process completed; it does not mean all cards are compatible.
Arduino's SD_MMC.end() does not return an unmount result, so the screen displays Unmount: done, which does not mean unmounting has been verified as successful. A display failure does not interrupt the TF test; the serial port DISPLAY separately reports the display result, and FINAL indicates the TF test result.
08_deep_sleep: Deep Sleep
Example Description
Displays a sleep prompt, puts the LR1121, e-paper, and detected AXP2602 into sleep, stops bus access, isolates the wireless pins, and then turns off and holds off the GPIO38 shared power supply. The default configuration is a 600-second (10-minute) timer and BOOT/GPIO0 low-level wake-up.
Operation Steps and Running Effect
After uploading, confirm the wake cause, radio pins isolated; shared power held off, and start deep sleep logs, release BOOT, and wait for the timed wake-up, or briefly press BOOT to wake up early. The USB port may disconnect during deep sleep; reconnect the serial monitor after waking up. To modify the timer period, adjust kWakeupSeconds in 08_deep_sleep.ino.
If SLEEP aborted appears, the program remains awake; troubleshoot the error and press RESET to retry. If the AXP2602 is not detected, it will prompt and continue running; this cannot be taken to mean that the fuel gauge has entered sleep. The basic shutdown process has been aligned with ESP-IDF example 08, and the actual current needs to be measured separately; for the process that includes shutting down Wi-Fi, BLE, MicroSD, and running tasks, see example 09.
09_comprehensive_demo: Comprehensive Example
Example Description
After power-on or wake-up, it runs a self-test, displays the BOARD TEST result page, and then enters RUNTIME. Runtime includes dual-core computation, memory stress, Wi-Fi APSTA, BLE passive scanning, and LoRa reception; the TF is read-only and no files are written.
Operation Steps
- Modify
app_config.hin the example directory to set the STA, SoftAP, and LoRa parameters. If STA is not configured, it does not affect SoftAP startup. - After checking the antenna and wireless parameters, upload and observe the self-test and runtime pages.
- Press KEY/GPIO1 to send one frame of LoRa for each stable press.
- Double-press BOOT/GPIO0 to enter sleep; during deep sleep, single-press BOOT to wake up, and check whether the self-test and runtime services are rebuilt.
Result Judgment
The serial port reports status every 30 seconds by default, and the screen refreshes every 5 minutes by default; transmit/receive events can trigger an earlier refresh. When a card, STA credentials, or LoRa peer is missing, judge based on the corresponding untested status; success in other items cannot be substituted for it. The BLE count includes duplicate advertisements and is not the number of unique devices.
This example does not enable timed wake-up. Arduino uses the native display and core libraries and does not use the ESP-IDF Board Manager/LVGL; the two cannot share build steps.
10_lr1121_lorawan: Class A OTAA
Example Description
Uses LoRaWAN 1.1 OTAA to activate or restore a session, periodically sends uplinks, and handles the Class A receive windows, saving the nonce and session state.
Operation Steps and Running Effect
Fill in the JoinEUI, DevEUI, NwkKey, and AppKey in lorawan_credentials.h in the example directory, verify the region object and server configuration in the .ino, and then upload. Observe the activation status and the incrementing FCntUp; the current application transmission period is 60 seconds, and it is also subject to protocol scheduling.
If the placeholder values are not replaced, the program displays CONFIG ERROR and stops wireless operations. For configuration and session saving instructions, see LoRaWAN Usage Instructions.
11_LoRaWAN_ABP: Class A ABP
Example Description
Directly configures or restores an ABP session without sending an OTAA Join Request. The current Arduino implementation uses the four independent session keys of LoRaWAN 1.1.
Operation Steps and Running Effect
Fill in the DevAddr, AppSKey, FNwkSIntKey, SNwkSIntKey, and NwkSEncKey in abp_credentials.h, and use the same MAC version and keys on the server. After uploading, check the session status and uplink counter; in addition to periodic transmission, you can also request transmission by pressing GPIO1.
Do not copy the same 1.0.x NwkSKey into the three 1.1 network key positions. Keep the local session consistent with the server frame counters.
12_LoRaWAN_Class_C: Continuous Reception
Example Description
Switches to Class C after completing OTAA, handles asynchronous downlinks, and periodically sends uplinks.
Operation Steps and Running Effect
Configure the device credentials in lorawan_credentials.h, enable Class C on the server, and verify RX2/RXC. After uploading, check Class C ready, then send downlinks from the server, and check the port, downlink count, and length.
Do not add deep sleep that stops reception during operation. The screen showing ready does not mean the server downlink has been received; you need to actually send a downlink and check the reception record.
13_LoRaWAN_Multicast: Static Multicast
Example Description
First establishes the device's own OTAA session, then enables static Class C multicast. The multicast counter is written to Preferences, and duplicate or rollback counts are rejected.
Operation Steps and Running Effect
In multicast_credentials.h, configure the independent OTAA credentials for each device and the shared multicast address, AppSKey, and NwkSKey for the same group. Configure the same multicast parameters on the server, wait for multicast ready, then send multicast downlinks, and check the multicast accepted and incrementing counters on each board.
This example does not include remote group creation, Class B, or full FUOTA. If the multicast state write fails, wireless operations will be disabled; the storage problem should be resolved first.