ESP32-UART-programming

In this post, we will see how the ESP32 UART peripheral can be programmed

UART stands for Universal Asynchronous Receiver Transmitter

  • ESP32 has 3 UART controllers
  • These controllers are connected to the GPIO matrix allowing you to assign the UART peripherals to any of the GPIO
  • Communication speed is up to 5 Mbps
  • All the 3 UART interfaces can be accessed by the DMA controller or directly by the CPU

If you look closely you can see other than the usual TX RX lines there are RTS and CTS lines.

  • what are RTS / CTS lines?

RTS / CTS flow control mechanism is part of the RS232 Standard. These 2 Lines help Transmitter and receiver to alert each other before transmission takes place.

  • RTS means Request to Send
  • CTS means Clear to Send

You can read more on this here flow-control.


ESP32 UART provides hardware management of the CTS and RTS signal lines & the corresponding software flow control.

Now Let's get into programming the UART peripheral

Set ESP32 Default Console Output

Esp-SDK uses menuconfig to set different configurations for the chip

  • By default, UART0 is selected as the controller for the console output
  • The UART0 is mapped to GPIO01(TXD0) & GPIO3(RXD0) pins

In the ESP32-devkit board, these GPIO lines are connected to the CP2101 USB-UART module. So whenever we use printf() in the code to print something the printf function is internally using UART0 peripheral. Additionally, this UART0 is also used by the bootloader to print its debug log and take the binary image from the host machine during the flash process

If you open menuconfig in any of the example projects you can see the default settings as

hassin@hassin-HP:~/esp/hello_world$ idf.py menuconfig

Code Analysis 

We will go through the esp-idf/examples/peripherals/uart/uart_echo code-link example to understand how we should use the UART of ESP32. this is a very basic project and does not use RTS CTS software flow control.

In this project, the code sets 2 GPIOs to work with the UART1 controller. Any data received at the UART1 controller is echoed back to the same UART controller i.e UART1

So you need to connect a USB-UART module to the UART1 based GPIO pins and open a terminal app in your host machine

First, we have to create & set a uart_config_t structure type that varies according to our need

    /* Configure parameters of an UART driver,
     * communication pins and install the driver */
    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
    };

Then we have to set the structure to one of the 3 UART controllers

uart_param_config(UART_NUM_1, &uart_config);

The following function sets the internal UART Signals to GPIO pins

uart_set_pin(UART_NUM_1, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS);

Afterward, we install the UART driver using the following SDK API

esp_err_t uart_driver_install(
  uart_port_t uart_num, 
  int rx_buffer_size, 
  int tx_buffer_size, 
  int queue_size, 
  QueueHandle_t* uart_queue, 
  int intr_alloc_flags);

understanding the API parameters is important. The following table describes it

Parameter type
Argument
                   Meaning

uart_port_t uart_num UART_NUM_1                        Set your UART controller
int rx_buffer_size BUF_SIZE*2                        The RX buffer size
int tx_buffer_size 0                        If 0 then TX function will block task until all data is sent
int queue_size 0
QueueHandle_t* uart_queue NULL                         If used then a new queue handle is created to provide access to UART events
int intr_alloc_flags 0                         Related to interrupt

We call the function with proper values

uart_driver_install(UART_NUM_1, BUF_SIZE * 2, 0, 0, NULL, 0);

The following function is used to read bytes from the UART buffer.

int uart_read_bytes(
  uart_port_t uart_num, 
  uint8_t* buf, 
  uint32_t length, 
  TickType_t ticks_to_wait);
int len = uart_read_bytes(UART_NUM_1, data, BUF_SIZE, 20 / portTICK_RATE_MS);

Then to Send data to the UART port from a given buffer and length the code use this function

int uart_write_bytes(
  uart_port_t uart_num, 
  const char* src, 
  size_t size);
uart_write_bytes(UART_NUM_1, (const char *) data, len);

As the UART driver's parameter tx_buffer_size is set to zero. This function will not return until all the data have been sent out. Otherwise, if the tx_buffer_size > 0, this function will return after copying all the data to the tx ring buffer & later UART ISR will move data from the ring buffer to TX FIFO gradually.


Build & Flash
hassin@hassin-HP:~/esp/esp-idf/examples/peripherals/uart/uart_echo$ idf.py -p /dev/ttyUSB0 flash monitor

Connection Connect the USB-UART module to the ESP32 board

Then open a Serial terminal app to send data to the UART1 controller, I have used Arduino IDE Serial terminal

Now whatever you send will get echoed back to your serial terminal App

0 comments:

Post a Comment

Categories

Pages

Firmware Engineer

My photo
Works on Firmware, Embedded Linux, Smart Metering, RTOS, IoT backend

Contact Form

Name

Email *

Message *

Copyrighted by Hassin. Powered by Blogger.