Skip to content

Lesson14_SPI_SX1262_LoRa: ESP32-P4 SX1262 LoRa Transmit and Receive Communication

1. Course Introduction

In this lesson, we use ESP-IDF to drive the SX1262 LoRa module through the SPI interface and the RadioLib library, implementing point-to-point wireless data transmission and reception. The lesson includes two projects—a transmitter (TX) and a receiver (RX)—requiring two ESP32-P4 development boards paired for use. The TX board sends an incrementing counter data packet TX_Hello World:N every second and displays the count on the screen; after receiving the packet, the RX board displays the RX_Hello World:N count along with RSSI and SNR values on the screen.

After flashing the program, the TX board's screen shows a white background with black TX_Hello World:N text, and the count increments every second; the RX board's screen displays the RX_Hello World:N count incrementing with each reception and shows RSSI and SNR in real time. Through this experiment, learners will complete the full wireless communication link validation covering SPI bus configuration, SX1262 LoRa initialization, interrupt-driven transmit/receive, and real-time LVGL display.

2. Learning Objectives

  • Be able to open the TX and RX projects of Lesson14 in ESP-IDF and set the target chip to esp32p4.
  • Be able to explain the SX1262 SPI connections (SCK/MISO/MOSI/NSS/IRQ/NRST/BUSY) and the function of each pin.
  • Be able to explain the meaning of the LoRa parameters (frequency 915 MHz, BW 125 kHz, SF7, CR7).
  • Be able to explain the working mechanism of interrupt-driven transmit/receive (setPacketSentAction/setPacketReceivedAction).
  • Be able to complete compilation and flashing of both boards, and observe the TX count incrementing, the RX count incrementing with reception, and real-time RSSI/SNR updates.

3. What You Need

  • Hardware: Two CrowPanel Advanced 7 / 9 / 10.1-inch ESP32-P4 HMI AI Display development boards; two USB Type-C data cables that support data transfer; two SX1262 LoRa modules, with one module connected to each development board.
  • Compatibility note: The 7 / 9 / 10.1-inch development boards share the same hardware and software code, differing only in board size; please select the appropriate model based on display size and use case.
  • Software: VS Code, ESP-IDF Extension (ESP-IDF v5.4 or later).
  • Project dependencies: Keep main/main_tx.c for the TX project, main/main_rx.c for the RX project, along with the peripheral/bsp_wireless and peripheral/bsp_illuminate components and the RadioLib managed component.
  • Configuration: target chip esp32p4; SPI3, SCK=GPIO8, MISO=GPIO7, MOSI=GPIO6, NSS=GPIO10, IRQ=GPIO27, NRST=GPIO28, BUSY=GPIO9; LoRa 915 MHz / 125 kHz / SF7 / CR7 / 22 dBm.

Code download link:

CrowPanel-Advanced-7inch-ESP32-P4-HMI-AI-Display-1024x600-IPS-Touch-Screen/example at master · Elecrow-RD/CrowPanel-Advanced-7inch-ESP32-P4-HMI-AI-Display-1024x600-IPS-Touch-Screen

4. Software Operation Steps

  1. Open the ESP-IDF Extension panel in VS Code, click Open ESP-IDF Project, and select the Lesson14_TX_SX1262_Wireless_Module folder (transmitter). Open TX project

  2. First, select the code execution environment ESP-IDF v5.4.2, set the flashing method to UART, then select the serial port corresponding to the development board. Next, click Set Espressif Device Target in the ESP-IDF Extension panel and select esp32p4. After the configuration is complete, the status bar should display ESP-IDF v5.4.2, UART, the required COM port, and ESP32-P4.

Click SDK Configuration Editor

  1. Click SDK Configuration Editor in the VS Code bottom status bar or the ESP-IDF extension panel, and wait for the configuration page to fully load before modifying parameters. If the page is still loading, do not run Build immediately.

Click SDK Configuration Editor

Wait for SDK Configuration Editor to finish loading

  1. Enter flash in the search box and ensure Flash SPI mode: QIO; Flash Sampling Mode: STR Mode; Flash SPI speed: 80 MHz; Flash size: 16 MB. These parameters should match the onboard Flash of the Advance-P4 board. Configure Flash parameters

  2. Enter wireless in the search box, check only Enable SX1262 config, and disable the wireless module configurations not used in this lesson, such as nRF2401, ESP32-C6, and ESP32-H2. This setting must be completed separately for both the TX and RX projects. Enable SX1262 wireless module configuration

  3. Then refer to "4. Software Operation Steps" in Lesson07_Turn_on_the_Screen to complete the detailed SDK configuration; the relevant configuration methods were covered in Lesson 7.

    Note: The LVGL font size used in this lesson is 42 pt; please modify it accordingly.

  4. After verifying the configuration is correct, click Save in the upper-right corner; confirm the changes are saved, then run Build to compile.

  5. Click Full Clean to clear the cache left by the previous compilation. Run this operation after the first compilation, when switching project configurations, or after modifying SDK parameters, to prevent old configurations from affecting the new build result. Run Full Clean

  6. Click Build to compile the TX project. On success, it outputs Project build complete. Compile TX project

  7. Connect the first development board, click Select Port to Use to select the corresponding serial port, then click Flash to flash the TX firmware. Flash TX firmware

  8. Open the project again and select Lesson14_RX_SX1262_Wireless_Module (receiver). Re-apply steps 2–7 to set the ESP-IDF version, UART serial port, target chip, Flash, and SX1262 configuration, then click Full Clean followed by Build to compile the RX project. Open RX project

  9. Connect the second development board, click Select Port to Use to select the corresponding serial port, then click Flash to flash the RX firmware. Flash RX firmware

  10. Select the serial ports corresponding to the TX and RX development boards respectively, and click Monitor to open the serial monitor. Confirm that the transmitter continuously outputs transmission logs and the receiver continuously outputs reception logs; press Ctrl + ] to exit the monitor. Open the serial monitor

  11. Finally, you can use the one-click operation button in the ESP-IDF status bar to sequentially perform compilation, flashing, and opening the serial monitor. Use this only after the project configuration, serial port, and code have all been confirmed correct; if you need to locate a problem, still follow the steps above one by one. One-click compile, flash, and open monitor

5. Hardware Operation Steps

  1. Confirm that the SX1262 module and antenna are properly connected on both development boards, and the LCD ribbon cable is plugged in.

Remember to supply the product with an additional power cable to ensure the development board has sufficient current and the display works properly.

Connect the two development boards and the SX1262 modules

  1. After resetting the TX board, observe whether the screen displays TX_Hello World:0 and increments the count every second.

  2. After resetting the RX board, observe whether the screen displays the LoRa RX Receiver title and the initial value RX_Hello World:0. Observe the RX initial interface

  3. Place the two boards at a close distance (e.g., within 1 meter), and observe whether the RX board count increments with TX transmissions and whether RSSI and SNR update in real time.

  4. Observe whether the TX board serial port prints TX msg: TX_Hello World:N to confirm it transmits once per second.

  5. Observe whether the RX board serial port prints RX: ... (RSSI: ..., SNR: ...) to confirm successful reception.

6. Key Code Explanation

bsp_sx_radio->begin(915.0, 125.0, 7, 7, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, 22, 8, 1.6);

This is the SX1262 LoRa parameter configuration: frequency 915 MHz, bandwidth 125 kHz, spreading factor SF7, coding rate CR7 (4/7), private sync word, transmit power 22 dBm, preamble 8 symbols, and 1.6 V TCXO voltage. TX and RX must use identical parameters to communicate. If the frequency or spreading factor differs, the RX will be unable to receive data.

bsp_sx_radio->setPacketSentAction(set_sx1262_tx_flag);

The TX side registers a transmit-complete interrupt callback. When the SX1262 finishes transmitting a frame, it triggers an IRQ, and the callback sets lora_transmittedFlag to true, prompting the main loop to send the next frame. This is a non-blocking transmission mechanism. If interrupts are not used and the blocking transmit() is used instead, the CPU will wait for transmission to complete, wasting processing time.

bsp_sx_radio->setPacketReceivedAction(set_sx1262_rx_flag);
bsp_sx_radio->startReceive();

The RX side registers a receive interrupt and starts continuous reception. When the SX1262 receives a complete LoRa data packet, it triggers an IRQ, and the callback sets lora_receivedFlag to true. The polling task detects this flag and then reads the data. If the polling interval is too long (e.g., 1000 ms), it may miss rapidly transmitted consecutive packets.

if (lora_transmittedFlag) {
    lora_transmittedFlag = false;
    ...
    lora_transmissionState = bsp_sx_radio->startTransmit((uint8_t *)text, tx_len + 1);
    return true;
}
return false;

TX transmission logic: it sends the next frame only after the previous frame has finished transmitting. startTransmit is a non-blocking call that returns immediately. If startTransmit is called before the previous frame is complete, it may overwrite data currently being transmitted and cause packet loss.

int state = bsp_sx_radio->readData(data, lora_received_len);
if (state == RADIOLIB_ERR_NONE) {
    ...
    rx_data_callback((const char *)data, ...);
} else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
    SX1262_ERROR("CRC error!");
}

RX read logic: readData reads the data and returns a status. A CRC check failure (RADIOLIB_ERR_CRC_MISMATCH) indicates the data was corrupted by interference and should be discarded rather than passed to the upper layer. If CRC errors are ignored and the data is used directly, it may display garbled characters.

7. Experimental Results

TX board:

I (xxx) MAIN: ---------- LoRa TX ----------
I (xxx) MAIN: LCD init success
I (xxx) MAIN: The wireless module initialization was successful.
I (xxx) SX1262: transmission finished!
I (xxx) MAIN: TX msg: TX_Hello World:1
I (xxx) MAIN: TX msg: TX_Hello World:2
The screen displays TX_Hello World:N, with N incrementing every second.

RX board:

I (xxx) MAIN: ---------- LoRa RX ----------
I (xxx) MAIN: LoRa RX receiver started, waiting for data...
I (xxx) SX1262: Received packet!
I (xxx) SX1262: Valid Data : TX_Hello World:1
I (xxx) SX1262: RSSI:-45.23 dBm
I (xxx) SX1262: SNR:9.50 dB
I (xxx) MAIN: RX: RX_Hello World:1 (RSSI: -45.2 dBm, SNR: 9.5 dB)
The screen displays RX_Hello World:N, with the count incrementing as packets are received and RSSI and SNR updating in real time. At close range, RSSI should be relatively strong (approximately −40 to −60 dBm), and SNR is typically positive (approximately 5 to 12 dB). If the RX count does not increment, check whether the LoRa parameters on both ends match and whether the antenna is properly connected; if RSSI is extremely low, move the boards closer or check the antenna connection.