1 /* Uart Events Example
2 
3    This example code is in the Public Domain (or CC0 licensed, at your option.)
4 
5    Unless required by applicable law or agreed to in writing, this
6    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7    CONDITIONS OF ANY KIND, either express or implied.
8 */
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include "freertos/FreeRTOS.h"
13 #include "freertos/task.h"
14 #include "esp_system.h"
15 #include "nvs_flash.h"
16 #include "driver/uart.h"
17 #include "freertos/queue.h"
18 #include "esp_log.h"
19 #include "sdkconfig.h"
20 
21 /**
22  * This is a example which echos any data it receives on UART back to the sender using RS485 interface in half duplex mode.
23 */
24 #define TAG "RS485_ECHO_APP"
25 
26 // Note: Some pins on target chip cannot be assigned for UART communication.
27 // Please refer to documentation for selected board and target to configure pins using Kconfig.
28 #define ECHO_TEST_TXD   (CONFIG_ECHO_UART_TXD)
29 #define ECHO_TEST_RXD   (CONFIG_ECHO_UART_RXD)
30 
31 // RTS for RS485 Half-Duplex Mode manages DE/~RE
32 #define ECHO_TEST_RTS   (CONFIG_ECHO_UART_RTS)
33 
34 // CTS is not used in RS485 Half-Duplex Mode
35 #define ECHO_TEST_CTS   (UART_PIN_NO_CHANGE)
36 
37 #define BUF_SIZE        (127)
38 #define BAUD_RATE       (CONFIG_ECHO_UART_BAUD_RATE)
39 
40 // Read packet timeout
41 #define PACKET_READ_TICS        (100 / portTICK_RATE_MS)
42 #define ECHO_TASK_STACK_SIZE    (2048)
43 #define ECHO_TASK_PRIO          (10)
44 #define ECHO_UART_PORT          (CONFIG_ECHO_UART_PORT_NUM)
45 
46 // Timeout threshold for UART = number of symbols (~10 tics) with unchanged state on receive pin
47 #define ECHO_READ_TOUT          (3) // 3.5T * 8 = 28 ticks, TOUT=3 -> ~24..33 ticks
48 
echo_send(const int port,const char * str,uint8_t length)49 static void echo_send(const int port, const char* str, uint8_t length)
50 {
51     if (uart_write_bytes(port, str, length) != length) {
52         ESP_LOGE(TAG, "Send data critical failure.");
53         // add your code to handle sending failure here
54         abort();
55     }
56 }
57 
58 // An example of echo test with hardware flow control on UART
echo_task(void * arg)59 static void echo_task(void *arg)
60 {
61     const int uart_num = ECHO_UART_PORT;
62     uart_config_t uart_config = {
63         .baud_rate = BAUD_RATE,
64         .data_bits = UART_DATA_8_BITS,
65         .parity = UART_PARITY_DISABLE,
66         .stop_bits = UART_STOP_BITS_1,
67         .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
68         .rx_flow_ctrl_thresh = 122,
69         .source_clk = UART_SCLK_APB,
70     };
71 
72     // Set UART log level
73     esp_log_level_set(TAG, ESP_LOG_INFO);
74 
75     ESP_LOGI(TAG, "Start RS485 application test and configure UART.");
76 
77     // Install UART driver (we don't need an event queue here)
78     // In this example we don't even use a buffer for sending data.
79     ESP_ERROR_CHECK(uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0));
80 
81     // Configure UART parameters
82     ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));
83 
84     ESP_LOGI(TAG, "UART set pins, mode and install driver.");
85 
86     // Set UART pins as per KConfig settings
87     ESP_ERROR_CHECK(uart_set_pin(uart_num, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS));
88 
89     // Set RS485 half duplex mode
90     ESP_ERROR_CHECK(uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX));
91 
92     // Set read timeout of UART TOUT feature
93     ESP_ERROR_CHECK(uart_set_rx_timeout(uart_num, ECHO_READ_TOUT));
94 
95     // Allocate buffers for UART
96     uint8_t* data = (uint8_t*) malloc(BUF_SIZE);
97 
98     ESP_LOGI(TAG, "UART start recieve loop.\r\n");
99     echo_send(uart_num, "Start RS485 UART test.\r\n", 24);
100 
101     while(1) {
102         //Read data from UART
103         int len = uart_read_bytes(uart_num, data, BUF_SIZE, PACKET_READ_TICS);
104 
105         //Write data back to UART
106         if (len > 0) {
107             echo_send(uart_num, "\r\n", 2);
108             char prefix[] = "RS485 Received: [";
109             echo_send(uart_num, prefix, (sizeof(prefix) - 1));
110             ESP_LOGI(TAG, "Received %u bytes:", len);
111             printf("[ ");
112             for (int i = 0; i < len; i++) {
113                 printf("0x%.2X ", (uint8_t)data[i]);
114                 echo_send(uart_num, (const char*)&data[i], 1);
115                 // Add a Newline character if you get a return charater from paste (Paste tests multibyte receipt/buffer)
116                 if (data[i] == '\r') {
117                     echo_send(uart_num, "\n", 1);
118                 }
119             }
120             printf("] \n");
121             echo_send(uart_num, "]\r\n", 3);
122         } else {
123             // Echo a "." to show we are alive while we wait for input
124             echo_send(uart_num, ".", 1);
125             ESP_ERROR_CHECK(uart_wait_tx_done(uart_num, 10));
126         }
127     }
128     vTaskDelete(NULL);
129 }
130 
app_main(void)131 void app_main(void)
132 {
133     //A uart read/write example without event queue;
134     xTaskCreate(echo_task, "uart_echo_task", ECHO_TASK_STACK_SIZE, NULL, ECHO_TASK_PRIO, NULL);
135 }
136