Skip to content

UART 2X is a debugging program utilizing two UARTs (1 and 2) to test TTL to RS-485 converter boards (XY-485) connected together over RS-485.

License

Notifications You must be signed in to change notification settings

K0I05/ESP32-S3_UART2X

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

UART to UART with TTL to RS-485 Converters

K0I05 License: MIT Language Framework Edited with VS Code Build with PlatformIO

UART 2X is a debugging program utilizing two UARTs (1 and 2) to test TTL to RS-485 converter boards (XY-485) connected together over RS-485. UART 1 is configured and programmed to transmit data and UART 2 is configured to receive data. A basic validation can be accomplished by wiring the microcontroller's GPIO 17 (UART1_TXD) pin to GPIO 3 (UART2_RXD) pin, when UART 1 transmits data to UART 2, the received data will be displayed through the serial monitor terminal.

Circuit Wiring

This project can be tested in two primary configurations: a basic UART loopback for initial validation and a full RS-485 setup using TTL to RS-485 converters. The following sections detail the wiring for each configuration.

Important Notes Before Wiring:

  • Power Supply: Ensure that both the ESP32-S3 and the TTL to RS-485 converter boards are powered correctly. Typically, they operate at 3.3V or 5V. Refer to the datasheets for your specific components.
  • Ground Connection: A common ground connection is essential for proper communication. Connect the ground pins of the ESP32-S3 and both TTL to RS-485 converter boards together.
  • RS-485 Termination: For longer RS-485 cable runs, you may need to add termination resistors (typically 120 ohms) at each end of the RS-485 bus to prevent signal reflections. For short distances, this is often not necessary.
  • Data Direction Control: Some RS-485 converter boards have a "DE" (Driver Enable) and "RE" (Receiver Enable) pin. These pins are used to control whether the transceiver is transmitting or receiving. For this example, we are not using these pins, and the boards are configured for automatic direction control.
  • XY-485: The XY-485 is a TTL to RS-485 converter board. It is used to convert the TTL signals from the ESP32-S3 to RS-485 signals. It is also used to convert the RS-485 signals back to TTL signals for the ESP32-S3.

1. Basic UART Loopback (TTL Level)

This configuration allows you to test the basic UART functionality of the ESP32-S3 without the RS-485 converters. It's a good first step to ensure that the UART peripherals are working correctly.

  • Wiring:
    • Connect GPIO 17 (UART1_TXD) to GPIO 3 (UART2_RXD).
    • Connect the ground pin of the ESP32-S3 to the ground of your power supply.
  • Purpose: This creates a loopback where data transmitted from UART 1 is directly received by UART 2.
  • Verification: After uploading the code, open the serial monitor. You should see the "Hello World!" message being transmitted and received, indicating that the basic UART communication is functional.

2. RS-485 Communication (with TTL to RS-485 Converters)

This configuration demonstrates communication between two RS-485 transceivers connected to the ESP32-S3. This is the full setup for testing RS-485 communication.

  • Components:

    • ESP32-S3 microcontroller.
    • Two TTL to RS-485 converter boards (e.g., XY-485).
    • Connecting wires.
    • Power supply.
  • Wiring Table:

    Connection ESP32-S3 Pin TTL to RS-485 Converter (Board 1) TTL to RS-485 Converter (Board 2)
    UART1 Transmit (TXD) GPIO 17 TTL1_TXD
    UART1 Receive (RXD) GPIO 18 TTL1_RXD
    UART2 Transmit (TXD) GPIO 1 TTL2_TXD
    UART2 Receive (RXD) GPIO 3 TTL2_RXD
    RS-485 A TTL1_RS485_A TTL2_RS485_A
    RS-485 B TTL1_RS485_B TTL2_RS485_B
    Ground GND GND GND
    Power 3.3V or 5V VCC VCC
  • Wiring Steps:

    1. Connect ESP32-S3 to Board 1:
      • Connect GPIO 17 (UART1_TXD) on the ESP32-S3 to the TTL1_TXD pin on the first TTL to RS-485 converter board.
      • Connect GPIO 18 (UART1_RXD) on the ESP32-S3 to the TTL1_RXD pin on the first TTL to RS-485 converter board.
    2. Connect ESP32-S3 to Board 2:
      • Connect GPIO 1 (UART2_TXD) on the ESP32-S3 to the TTL2_TXD pin on the second TTL to RS-485 converter board.
      • Connect GPIO 3 (UART2_RXD) on the ESP32-S3 to the TTL2_RXD pin on the second TTL to RS-485 converter board.
    3. Connect RS-485 Boards:
      • Connect the TTL1_RS485_A pin on the first board to the TTL2_RS485_A pin on the second board.
      • Connect the TTL1_RS485_B pin on the first board to the TTL2_RS485_B pin on the second board.
    4. Connect Power and Ground:
      • Connect the ground pins (GND) of the ESP32-S3 and both TTL to RS-485 converter boards together.
      • Connect the power pins (VCC) of both TTL to RS-485 converter boards to the appropriate power supply (3.3V or 5V, depending on your boards).
      • Connect the power pin (3.3V or 5V) of the ESP32-S3 to the appropriate power supply.
    5. Verify: Ensure all connections are secure and correct before applying power.
  • Purpose: This setup allows data to be transmitted from UART 1 on the ESP32-S3, converted to RS-485, sent over the RS-485 bus, converted back to TTL, and received by UART 2 on the ESP32-S3.

  • Verification: After uploading the code, open the serial monitor. You should see the "Hello World!" message being transmitted from UART 1 and received by UART 2, indicating successful RS-485 communication.

Circuit Diagram:

Refer to the circuit diagram below for a visual representation of the RS-485 wiring.

Circuit

Program Flow

The program utilizes FreeRTOS tasks to manage the UART communication, allowing for concurrent transmit and receive operations. The main steps are:

  1. Define UART GPIO Pins: Define the GPIO pins used for UART 1 (transmit) and UART 2 (receive). These pins are used to connect the ESP32-S3 to the TTL to RS-485 converter boards.
  2. Configure UARTs: Initialize UART 1 and UART 2, install the necessary drivers, and set the GPIO pins. This step configures the UART peripherals for communication.
  3. Create Receive Task: Create a FreeRTOS task (uart2_rx_task) to continuously monitor UART 2 for incoming data. This task is responsible for receiving data from the RS-485 bus (via the converter board) and processing it.
  4. Create Transmit Task: Create a FreeRTOS task (uart1_tx_task) to periodically transmit data over UART 1. This task is responsible for sending data out over the RS-485 bus (via the converter board).

Detailed Breakdown:

The program's operation can be broken down into the following phases:

A. Initialization Phase:

  1. UART Pin Definition: The program starts by defining the GPIO pins that will be used for UART communication. This is done using #define directives, as shown in the "UART Configuration" section.

    // UART 1 - tx
    #define UART1 UART_NUM_1
    #define UART1_TXD  (GPIO_NUM_17)
    #define UART1_RXD  (GPIO_NUM_18)
    
    // UART 2 - rx
    #define UART2 UART_NUM_2
    #define UART2_TXD  (GPIO_NUM_1)
    #define UART2_RXD  (GPIO_NUM_3)
    • Purpose: These definitions map the logical UART names (UART1, UART2) to the physical GPIO pins on the ESP32-S3.
  2. UART Configuration: The init_uarts() function is called to configure the UART peripherals.

    • uart_config_t: A structure is defined to hold the UART configuration parameters (baud rate, data bits, parity, stop bits, flow control, clock source).
    • uart_driver_install(): This function installs the UART driver for each UART, allocating the necessary resources (buffers, etc.).
    • uart_param_config(): This function applies the configuration parameters defined in the uart_config_t structure to each UART.
    • uart_set_pin(): This function assigns the previously defined GPIO pins to the UART peripherals.
    /**
     * @brief Initializes UART 1 and 2.
     */
    static inline void init_uarts( void ) {
        // configuration for UART 1 and 2
        const uart_config_t uart_config = {
            .baud_rate  = 115200,
            .data_bits  = UART_DATA_8_BITS,
            .parity     = UART_PARITY_DISABLE,
            .stop_bits  = UART_STOP_BITS_1,
            .flow_ctrl  = UART_HW_FLOWCTRL_DISABLE,
            .source_clk = UART_SCLK_DEFAULT,
        };
    
        // UART1 - tx
        uart_driver_install(UART1, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
        uart_param_config(UART1, &uart_config);
        uart_set_pin(UART1, UART1_TXD, UART1_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    
        // UART2 - rx
        uart_driver_install(UART2, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
        uart_param_config(UART2, &uart_config);
        uart_set_pin(UART2, UART2_TXD, UART2_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    }
    • Purpose: This step sets up the UART peripherals to be ready for communication.
  3. Task Creation: The xTaskCreatePinnedToCore() function is used to create the receive and transmit tasks.

    xTaskCreatePinnedToCore(uart2_rx_task, "uart2_rx_task", 
        1024 * 3, NULL, configMAX_PRIORITIES - 1, NULL, APP_CPU_NUM);
    xTaskCreatePinnedToCore(uart1_tx_task, "uart1_tx_task", 
        1024 * 3, NULL, configMAX_PRIORITIES - 2, NULL, APP_CPU_NUM);
    • xTaskCreatePinnedToCore(): This FreeRTOS function creates a new task and pins it to a specific CPU core.
    • uart2_rx_task and uart1_tx_task: These are the functions that implement the receive and transmit tasks, respectively.
    • "uart2_rx_task" and "uart1_tx_task": These are the names assigned to the tasks for debugging purposes.
    • 1024 * 3: This is the stack size allocated to each task (3KB).
    • NULL: This is the task parameter, which is not used in this example.
    • configMAX_PRIORITIES - 1 and configMAX_PRIORITIES - 2: These are the task priorities. Higher numbers indicate higher priority. The receive task has a higher priority than the transmit task.
    • NULL: This is the task handle, which is not used in this example.
    • APP_CPU_NUM: This macro specifies that the tasks should be pinned to the application CPU core.
    • Purpose: This step sets up the concurrent tasks that will handle the UART communication.

B. Operational Phase (Concurrent Tasks):

  1. Receive Task (uart2_rx_task):

    • Loop: The task enters an infinite loop (while (1)).
    • Read UART: uart_read_bytes() is called to read data from the UART 2 receive buffer.
    • Check for Data: If rx_bytes > 0, data has been received.
    • Process Data: The received data is null-terminated (data[rx_bytes] = 0;) to make it a valid C string.
    • Log Data: ESP_LOGI() and ESP_LOG_BUFFER_HEXDUMP() are used to print the received data to the serial monitor.
    • Flush Buffer: uart_flush(UART2) is used to clear the UART2 buffer.
    • Repeat: The loop continues, waiting for more data.
    • Cleanup: free(data) is used to release the memory allocated for the data buffer.
    • Delete Task: vTaskDelete(NULL) is used to delete the task.
    static void uart2_rx_task(void *pv_parameters) {
        static const char *RX_TASK_TAG = "UART2_RX_TASK";
        esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
        uint8_t* data = (uint8_t*)malloc(RX_BUF_SIZE + 1);
        while (1) {
            const int rx_bytes = uart_read_bytes(UART2, data, RX_BUF_SIZE, 1000 / portTICK_PERIOD_MS);
            if (rx_bytes > 0) {
                data[rx_bytes] = 0;
                ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%s'", rx_bytes, data);
                ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rx_bytes, ESP_LOG_INFO);
                uart_flush(UART2);
            }
        }
        free(data);
        vTaskDelete(NULL);
    }
    • Purpose: This task continuously monitors UART 2 for incoming data and processes it.
  2. Transmit Task (uart1_tx_task):

    • Loop: The task enters an infinite loop (while (1)).
    • Transmit Data: uart1_tx_data() is called to transmit the "Hello World!" message over UART 1.
    • Delay: vTaskDelay() is used to pause the task for 5 seconds (5000 milliseconds).
    • Repeat: The loop continues, transmitting the message every 5 seconds.
    • Delete Task: vTaskDelete(NULL) is used to delete the task.
static inline int uart1_tx_data(const char* log_name, const char* data) {
    const int len = strlen(data);
    const int tx_bytes = uart_write_bytes(UART_NUM_1, data, len);
    ESP_LOGI(log_name, "Wrote %d bytes", tx_bytes);
    return tx_bytes;
}

static void uart1_tx_task(void *pv_parameters) {
    static const char *TX_TASK_TAG = "UART1_TX_TASK";
    esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO);
    while (1) {
        uart1_tx_data(TX_TASK_TAG, "Hello World!");
        vTaskDelay(5000 / portTICK_PERIOD_MS);
    }
    vTaskDelete(NULL);
}
  • Purpose: This task periodically transmits data over UART 1.

C. Task Management:

  • FreeRTOS: The use of FreeRTOS allows the receive and transmit tasks to run concurrently. The FreeRTOS scheduler manages the execution of these tasks, switching between them as needed.
  • Task Priorities: The receive task has a higher priority than the transmit task. This ensures that incoming data is processed promptly.
  • Task Deletion: The vTaskDelete(NULL) function is used to delete the task when it is no longer needed.

Diagram:

A simplified diagram of the program flow is shown below:

+-------------------+ +-------------------+ +-------------------+ | Initialization |------>| Concurrent Tasks |------>| Task Management | +-------------------+ +-------------------+ +-------------------+ | - Define UART | | - Receive Task | | - FreeRTOS | | Pins | | (UART 2) | | Scheduler | | - Configure UARTs | | - Transmit Task | | - Task Priorities | | - Create Tasks | | (UART 1) | | - Task Deletion | +-------------------+ +-------------------+ +-------------------+

Next Steps

RS-485 supports inexpensive local networks and multidrop communications links. It is generally accepted that RS-485 can be used with data rates up to 10 Mbit/s or, at lower speeds, distances up to 1,200 m (4,000 ft). RS-485 with MODBUS is widely used in instrumentation applications and would be a suggested next step to explore. If you would like to explore further, feel free to review the MODBUS RTU example.

Copyright (c) 2025 Eric Gionet ([email protected])

About

UART 2X is a debugging program utilizing two UARTs (1 and 2) to test TTL to RS-485 converter boards (XY-485) connected together over RS-485.

Topics

Resources

License

Stars

Watchers

Forks