-
Notifications
You must be signed in to change notification settings - Fork 112
feat(rmt_uart): add soft uart component #502
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Adds a new software-emulated UART component using the ESP32 RMT peripheral, including encoder, decoder, device API, and an example.
- Introduces
rmt_uart_encoder
for framing bytes into RMT symbols. - Implements
rmt_uart
device API for transmit, receive, decode, and lifecycle management. - Provides public headers, CMake component registration, example application, and README.
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
File | Description |
---|---|
src/rmt_uart_encoder.h | Header for RMT UART encoder creation API |
src/rmt_uart_encoder.c | Implementation of UART-to-RMT encoder logic |
src/rmt_uart.c | Core RMT UART device implementation (tx, rx, decode) |
include/rmt_uart.h | Public configuration and API declarations |
include/rmt_uart_type.h | Type definitions and callback signatures |
example/main/soft_uart_main.c | Sample application showing transmit/receive usage |
example/main/idf_component.yml & CMake | Example component registration |
example/README.md | Documentation and usage instructions |
CMakeLists.txt | Component build registration |
Comments suppressed due to low confidence (2)
rmt_soft_uart/src/rmt_uart.c:4
- License identifier differs from other files (Apache-2.0). Ensure consistent licensing across the component.
* SPDX-License-Identifier: Unlicense OR CC0-1.0
rmt_soft_uart/src/rmt_uart_encoder.c:24
- Critical encoding logic is introduced here but lacks accompanying unit tests to verify framing and state transitions.
static size_t rmt_encode_uart(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
e4257c1
to
8bc6033
Compare
8bc6033
to
c0bbf11
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds a new soft UART component that uses the RMT peripheral for UART signal emulation. Key changes include the implementation of UART encoding/decoding in new source and header files, integration with ESP-IDF component configuration and CI workflows, and an example demonstrating usage of the component.
Reviewed Changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated no comments.
File | Description |
---|---|
soft_uart/src/rmt_uart_encoder.[ch] | New encoder implementation with state-machine for UART framing. |
soft_uart/src/rmt_uart.c | Core driver implementation for transmitting/receiving via RMT. |
soft_uart/include/*.h | Public API and type definitions for the soft UART component. |
Various example and config files | Example application, component manifest, and CI integration. |
Comments suppressed due to low confidence (1)
soft_uart/src/rmt_uart_encoder.c:103
- The 'state' field of the allocated encoder is not explicitly initialized. To ensure predictable behavior of the state machine in rmt_encode_uart(), initialize uart_encoder->state to RMT_ENCODING_RESET right after allocation.
rmt_uart_encoder_t *uart_encoder = rmt_alloc_encoder_mem(sizeof(rmt_uart_encoder_t));
c0bbf11
to
b2ee24b
Compare
b2ee24b
to
33e8a0e
Compare
33e8a0e
to
0b76636
Compare
// [N + 1 + (1 or 2)] Stop bit (always 1) | ||
|
||
// extract the data byte | ||
uint8_t data_byte = (decode_context->raw_data >> 1) & ((1 << data_bits) - 1); |
Check warning
Code scanning / clang-tidy
Left shift by '254' overflows the capacity of 'int' [clang-analyzer-core.BitwiseShift] Warning
// [N + 1 + (1 or 2)] Stop bit (always 1) | ||
|
||
// extract the data byte | ||
uint8_t data_byte = (decode_context->raw_data >> 1) & ((1 << data_bits) - 1); |
Check warning
Code scanning / clang-tidy
Left shift by '255' overflows the capacity of 'int' [clang-analyzer-core.BitwiseShift] Warning
|
||
// do memory copy, the pingpong buffer should not be very large, so the memory copy should be fast | ||
if (edata->flags.is_last) { | ||
memcpy(rx_context->rx_symbols_buf + *read_symbol_index, edata->received_symbols, edata->num_symbols * sizeof(rmt_symbol_word_t)); |
Check warning
Code scanning / clang-tidy
Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning
} | ||
*read_symbol_index = 0; | ||
} else { | ||
memcpy(rx_context->rx_symbols_buf + *read_symbol_index, edata->received_symbols, edata->num_symbols * sizeof(rmt_symbol_word_t)); |
Check warning
Code scanning / clang-tidy
Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning
0b76636
to
fe76581
Compare
#include <stddef.h> | ||
#include "soc/soc_caps.h" | ||
#include "driver/rmt_types.h" | ||
#include "sdkconfig.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not used
#include <stdbool.h> | ||
#include <stdlib.h> | ||
#include <stddef.h> | ||
#include "soc/soc_caps.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not used by this header file
if(CONFIG_SOC_RMT_SUPPORTED) | ||
list(APPEND srcs "src/uart_emu_rmt.c" "src/uart_emu_rmt_encoder.c") | ||
endif() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
include($ENV{IDF_PATH}/tools/cmake/version.cmake)
|
||
[](https://components.espressif.com/components/espressif/uart_emu) | ||
|
||
This directory contains an implementation for software UART. Currently only RMT is supported as the software UART backend. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's hard if it's a hardware UART or software UART.. because RMT is still a hardware.
This directory contains an implementation for software UART. Currently only RMT is supported as the software UART backend. | |
This directory contains an implementation of UART driver emulated in various ways. Currently only RMT is supported as the backend. |
|
||
# Programming Guide | ||
|
||
- [UART EMU](index.md) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- [UART EMU](index.md) | |
- [UART Emulator](index.md) |
@@ -0,0 +1,8 @@ | |||
[book] | |||
title = "UART EMU" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
title = "UART EMU" | |
title = "UART Emulator Driver" |
@@ -0,0 +1,71 @@ | |||
# UART EMU |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# UART EMU | |
# UART Emulator Programming Guide |
@@ -0,0 +1,71 @@ | |||
# UART EMU | |||
|
|||
## Allocate UART EMULATOR Object with RMT Backend |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
## Allocate UART EMULATOR Object with RMT Backend | |
## Allocate UART Object with RMT Backend |
## API Documentation | ||
|
||
For detailed API documentation, please refer to the header files: | ||
- [uart_emu.h](./include/uart_emu.h) - Main public API |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After the Markdown file is compiled into html and hosted on the Github pages, user can't find this link.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Luckily this error is also caught by the CI.
.rx_io_num = UART_EMU_RX_PIN, | ||
.baud_rate = UART_EMU_BAUD_RATE, | ||
.data_bits = UART_EMU_DATA_8_BITS, | ||
.stop_bits = UART_EMU_STOP_BITS_1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I the a naming inconsistent in the UART_EMU_DATA_8_BITS
and UART_EMU_STOP_BITS_1
uart_emu_rmt_config_t rmt_config = { | ||
.tx_trans_queue_depth = UART_EMU_RMT_TX_TRANS_QUEUE_DEPTH, | ||
.tx_mem_block_symbols = UART_EMU_RMT_MEM_BLOCK_SYMBOLS, | ||
.rx_mem_block_symbols = UART_EMU_RMT_MEM_BLOCK_SYMBOLS, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is part of the programming guide, please add some comments beside the code, explaning how user can set these values
version: "1.0.0" | ||
description: Driver for UART emulator | ||
url: https://github.com/espressif/idf-extra-components/tree/master/uart_emu | ||
issues: "https://github.com/espressif/idf-extra-components/issues" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing repository
and documentation
#define UART_EMU_RMT_MEM_BLOCK_SYMBOLS 1024 | ||
#else | ||
#define UART_EMU_RMT_MEM_BLOCK_SYMBOLS SOC_RMT_MEM_WORDS_PER_CHANNEL | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to expose the SOC_RMT_MEM_WORDS_PER_CHANNEL
and SOC_RMT_SUPPORT_DMA
to the user's project. Refer to how led_strip handles it
// Set to 1 to use DMA for driving the LED strip, 0 otherwise
// Please note the RMT DMA feature is only available on chips e.g. ESP32-S3/P4
#define LED_STRIP_USE_DMA 0
#if LED_STRIP_USE_DMA
// Numbers of the LED in the strip
#define LED_STRIP_LED_COUNT 256
#define LED_STRIP_MEMORY_BLOCK_WORDS 1024 // this determines the DMA block size
#else
// Numbers of the LED in the strip
#define LED_STRIP_LED_COUNT 24
#define LED_STRIP_MEMORY_BLOCK_WORDS 0 // let the driver choose a proper memory block size automatically
#endif // LED_STRIP_USE_DMA
uart_emu_event_tx_callbacks_t uart_tx_cbs = { | ||
.on_tx_trans_done = uart_emu_rmt_tx_event_cbs, | ||
}; | ||
ESP_ERROR_CHECK(uart_emu_register_tx_event_callbacks(uart_device, &uart_tx_cbs, xTaskGetCurrentTaskHandle())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add some comment on why we passed in a task handle?
// create a task to read data from the UART | ||
xTaskCreate(uart_read_task, "uTask", 4096, uart_device, 4, NULL); | ||
|
||
char sendbuf[] = "RMT UART, transmission! RMT UART, transmission! RMT UART, transmission! RMT UART, transmission! RMT UART, transmission! RMT UART, transmission! RMT UART, transmission!"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question, can we use char *sendbuf = "xxx";
to reduce the use of the stack? I don't know if the transmit function only support a buffer from a stack?
|
||
int count = 0; | ||
while (1) { | ||
if (!ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(50))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the transmit is fast, after you call uart_emu_transmit
for 16 times, you can only get notified by 15 times or fewer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in this example, is the trans done event callback necessary? How can we make it more practical?
while (1) { | ||
/* Read from the UART */ | ||
ESP_ERROR_CHECK(uart_emu_receive(uart_device, (uint8_t *)receive_symbols, UART_EMU_RMT_RX_PINGPONG_BUFFER_SIZE * sizeof(rmt_symbol_word_t))); | ||
if (xQueueReceive(receive_queue, &rx_done_event_data, portMAX_DELAY)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how can we receive a long package? the uart_emu_rmt_rx_event_cbs
will be called multiple times. How many times do you want the user to call the uart_emu_receive
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we can refer to the twai onchip driver, offer a "rx_from_isr" function 🤔
Checklist
url
field definedChange description
Closes espressif/esp-idf#10128