Skip to main content

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.

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.

Setting Up the Development Environment

Install Arduino IDE

Please refer to the Install and Configure Arduino IDE Tutorial to install the Arduino IDE and add ESP32 board support.

Select Board and Port

After connecting the ESP32-C5-Touch-LCD-1.69 to your computer, select the corresponding serial port in the "Tools" menu.

Install Example Libraries

The Arduino examples are located in the example/arduino/examples directory. Before running an example, first extract example/arduino/ESP32_C5_Touch_LCD_1in69.zip, then copy the extracted library into the Arduino default libraries directory.

The Arduino libraries folder is typically located at:

C:/Users/<username>/Documents/Arduino/libraries

You can also check the "Sketchbook location" in Arduino IDE via "File > Preferences", and find the libraries folder under that path.

Example

ExampleBasic Description
01_RGB_TestScreen color cycling test
02_Mic_Speaker_TestMicrophone and speaker test
03_IMU_TestIMU test
04_Bat_TestBattery detection test
05_RTC_TestRTC test
06_LVGL_Demo_TestLVGL example test

01_RGB_Test

Hardware Connection

  • Connect the development board to a computer using a USB cable.

Code Analysis

RGB color cycling test code
static const uint16_t Colors[] = {
0xF800, // Red
0x07E0, // Green
0x001F, // Blue
0xFFFF, // White
0x0000, // Black
};

static const char *ColorNames[] = {
"R", "G", "B", "W", "BL",
};

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

if (!bsp_display_init()) {
Serial.println("bsp_display_init failed");
while (true) {
delay(1000);
}
}

bsp_display_backlight_on();
bsp_display_brightness_set(100);
}

void loop(void)
{
bsp_display_fill(Colors[color_index]);
Serial.printf("Show color: %s (%u)\n", ColorNames[color_index], color_index);

color_index++;
if (color_index >= (sizeof(Colors) / sizeof(Colors[0]))) {
color_index = 0;
}

delay(2000);
}

Code Explanation

  • Colors[] / ColorNames[]: RGB565 color values and name arrays (red/green/blue/white/black) for cycling through full-screen fills.
  • bsp_display_init(): Initializes the SPI bus and ST7789 LCD panel.
  • bsp_display_backlight_on(): Turns on the LCD backlight.
  • bsp_display_brightness_set(100): Sets backlight brightness to 100%.
  • bsp_display_fill(Colors[color_index]): Fills the entire screen with the specified RGB565 color.
  • Serial.printf(...): Outputs the current color name and index via serial for debugging.

Expected Behavior

  • The screen displays pure colors in sequence: red, green, blue, white, black, each for 2 seconds before switching.
  • The serial port outputs the current color name and index every 2 seconds.

ESP32-C5-Touch-LCD-1.69 Arduino 01 RGB


02_Mic_Speaker_Test

Hardware Connection

  • Connect the development board to a computer using a USB cable.

Code Analysis

Microphone loopback playback code
constexpr size_t audio_frame_bytes = 1024;
constexpr uint8_t speaker_volume = 70;
constexpr uint8_t mic_gain_db = 18;

uint8_t audio_buffer[audio_frame_bytes];

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

if (!bsp_audio_init()) {
Serial.println("bsp_audio_init failed");
return;
}

bsp_audio_set_speaker_volume(speaker_volume);
bsp_audio_set_mic_gain(mic_gain_db);

Serial.println("microphone loopback to speaker");
}

void loop()
{
size_t bytes_read = 0;
size_t bytes_written = 0;

if (!bsp_audio_read(audio_buffer, sizeof(audio_buffer), &bytes_read) || (bytes_read == 0)) {
Serial.println("bsp_audio_read failed");
delay(10);
return;
}

if (!bsp_audio_write(audio_buffer, bytes_read, &bytes_written) || (bytes_written != bytes_read)) {
Serial.println("bsp_audio_write failed");
delay(10);
}
}

Code Explanation

  • bsp_audio_init(): Initializes the I2S bus and ES8311 codec.
  • bsp_audio_set_speaker_volume(70): Sets speaker volume to 70.
  • bsp_audio_set_mic_gain(18): Sets microphone gain to 18dB.
  • bsp_audio_read(audio_buffer, ...): Reads 1024 bytes of audio data from the microphone.
  • bsp_audio_write(audio_buffer, ...): Writes the read audio data to the speaker, implementing real-time loopback.

Expected Behavior

  • Serial output shows microphone loopback to speaker.
  • Speaking into the microphone allows real-time playback from the speaker.

03_IMU_Test

Hardware Connection

  • Connect the development board to a computer using a USB cable.

Code Analysis

QMI8658 initialization and data reading code
#define QMI8658_I2C_ADDRESS 0x6B

static QMI8658 imu(Wire);
static AccelData accel_data = { 0 };
static GyroData gyro_data = { 0 };

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

bsp_display_brightness_init();
bsp_display_brightness_set(100);

if (!bsp_i2c_init()) {
Serial.println("I2C init failed");
while (true) {
delay(1000);
}
}

imu.init(imu_calibration, QMI8658_I2C_ADDRESS);
imu.setAccelRange(8);
imu.setGyroRange(512);
imu.setAccelODR(1000);
imu.setGyroODR(1000);

Serial.println("QMI8658 ready");
}

void loop(void)
{
imu.update();
imu.getAccel(&accel_data);
imu.getGyro(&gyro_data);

Serial.print("ACC[g] ");
Serial.print(accel_data.accelX, 3);
Serial.print(", ");
Serial.print(accel_data.accelY, 3);
Serial.print(", ");
Serial.print(accel_data.accelZ, 3);
Serial.print(" GYRO[dps] ");
Serial.print(gyro_data.gyroX, 3);
Serial.print(", ");
Serial.print(gyro_data.gyroY, 3);
Serial.print(", ");
Serial.print(gyro_data.gyroZ, 3);
Serial.print(" TEMP[C] ");
Serial.println(imu.getTemp(), 2);

delay(100);
}

Code Explanation

  • bsp_i2c_init(): Initializes the I2C bus (SDA=GPIO8, SCL=GPIO9, 400kHz).
  • imu.init(imu_calibration, QMI8658_I2C_ADDRESS): Initializes the QMI8658 with I2C address 0x6B.
  • imu.setAccelRange(8) / imu.setGyroRange(512): Sets accelerometer range to ±8g and gyroscope range to ±512dps.
  • imu.setAccelODR(1000) / imu.setGyroODR(1000): Sets accelerometer and gyroscope output data rate to 1000Hz.
  • imu.update(): Updates sensor data.
  • imu.getAccel(&accel_data) / imu.getGyro(&gyro_data): Reads accelerometer and gyroscope data.
  • imu.getTemp(): Reads temperature data.

Expected Behavior

  • After serial output QMI8658 ready, it prints accelerometer (g), gyroscope (dps), and temperature (°C) data every 100ms.
  • When the development board is slightly tilted or rotated, the accelerometer and gyroscope data will change accordingly.

ESP32-C5-Touch-LCD-1.69 Arduino 03 IMU


04_Bat_Test

Hardware Connection

  • Connect the development board to a computer using a USB cable.
  • Connect a Lithium battery to the development board.

Code Analysis

Battery information reading and display code
static const uint16_t battery_capacity_mah = 1500;

static const bsp_display_lvgl_partial_cfg_t battery_display_cfg = {
.use_psram = false,
.double_buffer = false,
.buffer_height = 120,
};

static void bat_update_label(const bsp_bat_info_t *bat_info)
{
const char *battery_state = "Idle";
const char *battery_note = "";

battery_state = (bat_info->ma > 0) ? "Charging" : ((bat_info->ma < 0) ? "Discharging" : "Idle");
battery_note = (bat_info->ma == 0) ? "battery not connected or full" : "battery connected";

lv_label_set_text_fmt(battery_label,
"Battery Test\n"
"State: %s\n"
"Voltage: %u mV\n"
"Current: %d mA\n"
"SOC: %u %%\n"
"Temp: %d C\n"
"Capacity: %u mAh\n"
"%s",
battery_state,
bat_info->mv,
bat_info->ma,
bat_info->soc,
bat_info->tc,
battery_capacity_mah,
battery_note);
}

void setup(void)
{
bsp_display_start_partial(&battery_display_cfg);
bsp_display_brightness_set(100);
bsp_bat_init(battery_capacity_mah);

bsp_display_lock(0);
battery_label = lv_label_create(lv_scr_act());
lv_obj_align(battery_label, LV_ALIGN_TOP_LEFT, 10, 10);
lv_label_set_text(battery_label, "Battery Test\nBattery status updating");
bsp_display_unlock();
}

void loop(void)
{
bsp_bat_info_t bat_info = {};

if (!bsp_get_bat_info(&bat_info)) {
Serial.println("battery info update failed");
return;
}

if (bat_info_changed(&battery_last_info, &bat_info)) {
if (bsp_display_lock(0)) {
bat_update_label(&bat_info);
battery_last_info = bat_info;
bsp_display_unlock();
}
}

delay(1000);
}

Code Explanation

  • bsp_display_start_partial(&battery_display_cfg): Starts LVGL in partial refresh mode to reduce framebuffer memory usage.
  • bsp_bat_init(battery_capacity_mah): Initializes the BQ27220 fuel gauge with battery capacity set to 1500mAh.
  • bsp_get_bat_info(&bat_info): Reads battery information (voltage/current/SOC/temperature, etc.).
  • bsp_display_lock(0) / bsp_display_unlock(): Acquires/releases the LVGL mutex for thread safety.
  • lv_label_set_text_fmt(battery_label, ...): Formats and updates the battery information label.
  • bat_info_changed(...): Checks whether battery data has changed to avoid unnecessary refreshes.

Expected Behavior

  • The screen displays battery status information: State (Charging/Discharging/Idle), Voltage (mV), Current (mA), SOC (%), Temperature (°C), Capacity (mAh).
  • Serial output also shows battery data.
  • When a battery is connected and current is non-zero, the state shows Charging or Discharging; when no battery is connected or fully charged, it shows Idle.

ESP32-C5-Touch-LCD-1.69 Arduino 04 Battery


05_RTC_Test

Hardware Connection

  • Connect the development board to a computer using a USB cable.

Code Analysis

RTC initialization and time reading code
static PCF85063A rtc(Wire);

static void rtc_set_to_build_time(void)
{
struct tm now_tm = {};
const char *build_date = __DATE__;
const char *build_time = __TIME__;

now_tm.tm_year = ((build_date[7] - '0') * 1000 + (build_date[8] - '0') * 100 +
(build_date[9] - '0') * 10 + (build_date[10] - '0')) - 1900;
now_tm.tm_mon = month_from_build_date(build_date);
now_tm.tm_mday = (build_date[4] == ' ') ? (build_date[5] - '0')
: ((build_date[4] - '0') * 10 + (build_date[5] - '0'));
now_tm.tm_hour = (build_time[0] - '0') * 10 + (build_time[1] - '0');
now_tm.tm_min = (build_time[3] - '0') * 10 + (build_time[4] - '0');
now_tm.tm_sec = (build_time[6] - '0') * 10 + (build_time[7] - '0');

rtc.set(&now_tm);
}

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

bsp_display_brightness_init();
bsp_display_brightness_set(100);

bsp_i2c_init();
rtc.begin();

if (rtc.oscillator_stop()) {
Serial.println("RTC lost power, set to build time");
rtc_set_to_build_time();
} else {
Serial.println("RTC running");
}
}

void loop(void)
{
time_t current_time = rtc.time(NULL);
struct tm *now_tm = localtime(&current_time);

Serial.printf("%04d-%02d-%02d %02d:%02d:%02d\r\n",
now_tm->tm_year + 1900,
now_tm->tm_mon + 1,
now_tm->tm_mday,
now_tm->tm_hour,
now_tm->tm_min,
now_tm->tm_sec);

delay(1000);
}

Code Explanation

  • bsp_i2c_init(): Initializes the I2C bus.
  • rtc.begin(): Initializes the PCF85063A RTC chip.
  • rtc.oscillator_stop(): Checks whether the RTC oscillator has stopped (power loss); returns true if time is lost.
  • rtc_set_to_build_time(): Sets RTC time using the compile time (__DATE__ / __TIME__).
  • rtc.time(NULL): Reads the RTC timestamp.
  • localtime(&current_time): Converts timestamp to local time structure for formatted output.

Expected Behavior

  • Serial output shows RTC running or RTC lost power, set to build time.
  • Then outputs time in YYYY-MM-DD HH:MM:SS format every second.

ESP32-C5-Touch-LCD-1.69 Arduino 05 RTC


06_LVGL_Demo_Test

Hardware Connection

  • Connect the development board to a computer using a USB cable.

Code Analysis

LVGL Benchmark initialization code
static const bsp_display_lvgl_full_frame_cfg_t lgvl_config = {
.use_psram = true,
.double_buffer = true,
.full_refresh = true,
};

void setup(void)
{
Serial.begin(115200);
bsp_display_start_full_frame(&lgvl_config);
bsp_display_brightness_set(100);

bsp_display_lock(0);
lv_demo_benchmark_set_max_speed(true);
lv_demo_benchmark();
bsp_display_unlock();
}

void loop(void)
{
delay(1000);
}

Code Explanation

  • bsp_display_start_full_frame(&lgvl_config): Starts LVGL in full-frame mode with PSRAM, double buffering, and full refresh enabled for best display performance.
  • bsp_display_brightness_set(100): Sets backlight brightness to 100%.
  • bsp_display_lock(0) / bsp_display_unlock(): Acquires/releases the LVGL mutex for thread-safe UI operations.
  • lv_demo_benchmark_set_max_speed(true): Sets benchmark to maximum speed mode.
  • lv_demo_benchmark(): Starts the LVGL benchmark performance test.

Expected Behavior

  • The screen sequentially displays various LVGL benchmark test scenes (rectangle, shadow, text, image, animation, and other rendering performance tests).
  • After the test completes, a summary of FPS scores is displayed.