-
Notifications
You must be signed in to change notification settings - Fork 6
Feature/peripheral rmt simple #15
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # The following five lines of boilerplate have to be in your project's | ||
| # CMakeLists in this exact order for cmake to work correctly | ||
| cmake_minimum_required(VERSION 3.16) | ||
|
|
||
| include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||
| project(rmt_simple_tx) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| idf_component_register(SRCS "main.c" | ||
| INCLUDE_DIRS ".") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| #include <stdio.h> | ||
| #include <string.h> | ||
| #include "freertos/FreeRTOS.h" | ||
| #include "freertos/task.h" | ||
| #include "driver/rmt_tx.h" | ||
|
|
||
| void app_main(void) | ||
| { | ||
| rmt_tx_channel_config_t tx_channel_cfg = { | ||
| .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, | ||
| .clk_src = RMT_CLK_SRC_DEFAULT, | ||
| .resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us | ||
| .trans_queue_depth = 4, | ||
| .gpio_num = GPIO_NUM_4, | ||
| .intr_priority = 3 | ||
| }; | ||
| rmt_channel_handle_t tx_channel = NULL; | ||
| rmt_new_tx_channel(&tx_channel_cfg, &tx_channel); | ||
|
|
||
|
Comment on lines
+17
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Check and surface errors from RMT API calls. The example currently ignores return codes. Wrapping API calls with ESP_ERROR_CHECK improves debuggability and prevents silent failures. Apply this diff: #include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/rmt_tx.h"
+#include "esp_err.h"
void app_main(void)
{
@@
rmt_channel_handle_t tx_channel = NULL;
- rmt_new_tx_channel(&tx_channel_cfg, &tx_channel);
+ ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_channel_cfg, &tx_channel));
@@
- rmt_new_bytes_encoder(&bytes_enc_config, &bytes_encoder);
- rmt_enable(tx_channel);
+ ESP_ERROR_CHECK(rmt_new_bytes_encoder(&bytes_enc_config, &bytes_encoder));
+ ESP_ERROR_CHECK(rmt_enable(tx_channel));
@@
- rmt_transmit(tx_channel, bytes_encoder, (uint8_t[]) {
+ ESP_ERROR_CHECK(rmt_transmit(tx_channel, bytes_encoder, (uint8_t[]) {
0x05
- }, 1, &transmit_config); // For 0x05, it's actually 8-bit data, corresponding to 0000 0101
+ }, 1, &transmit_config)); // For 0x05, it's actually 8-bit data, corresponding to 0000 0101
vTaskDelay(500 / portTICK_PERIOD_MS);Also applies to: 38-40, 45-49, 1-6 🤖 Prompt for AI Agents |
||
| rmt_encoder_handle_t bytes_encoder = NULL; | ||
|
|
||
| // Encode bit 0 and 1 | ||
| rmt_bytes_encoder_config_t bytes_enc_config = { | ||
| .bit0 = { | ||
| .level0 = 1, | ||
| .duration0 = 1, // 1us | ||
| .level1 = 0, | ||
| .duration1 = 1, // 1us | ||
| }, // For bit 0: first high level for 1us, then low level for 1us | ||
| .bit1 = { | ||
| .level0 = 1, | ||
| .duration0 = 9, // 9us | ||
| .level1 = 0, | ||
| .duration1 = 3, // 3us | ||
| }, // For bit 1: first high level for 9us, then low level for 3us | ||
| }; | ||
|
|
||
| rmt_new_bytes_encoder(&bytes_enc_config, &bytes_encoder); | ||
| rmt_enable(tx_channel); | ||
|
|
||
| rmt_transmit_config_t transmit_config = { | ||
| .loop_count = 0, // no loop | ||
| }; | ||
|
|
||
| while (1) { | ||
| rmt_transmit(tx_channel, bytes_encoder, (uint8_t[]) { | ||
| 0x05 | ||
| }, 1, &transmit_config); // For 0x05, it's actually 8-bit data, corresponding to 0000 0101 | ||
| vTaskDelay(500 / portTICK_PERIOD_MS); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| CONFIG_IDF_TARGET="esp32s3" | ||
| CONFIG_IDF_TARGET_ESP32S3=y | ||
|
|
||
| CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # For more information about build system see | ||
| # https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html | ||
| # The following five lines of boilerplate have to be in your project's | ||
| # CMakeLists in this exact order for cmake to work correctly | ||
| cmake_minimum_required(VERSION 3.16) | ||
|
|
||
| include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||
| project(ws2812_simple_encoder) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| idf_component_register(SRCS "main.c" | ||
| INCLUDE_DIRS ".") |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,102 @@ | ||||||||||||||||||||||||||
| #include <stdio.h> | ||||||||||||||||||||||||||
| #include <string.h> | ||||||||||||||||||||||||||
| #include "freertos/FreeRTOS.h" | ||||||||||||||||||||||||||
| #include "freertos/task.h" | ||||||||||||||||||||||||||
| #include "driver/rmt_tx.h" | ||||||||||||||||||||||||||
| #include "esp_log.h" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| static const char *TAG = "WS2812"; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| static const rmt_symbol_word_t ws2812_zero = { | ||||||||||||||||||||||||||
| .level0 = 1, | ||||||||||||||||||||||||||
| .duration0 = 4, /*!< 0.4us */ | ||||||||||||||||||||||||||
| .level1 = 0, | ||||||||||||||||||||||||||
| .duration1 = 9, /*!< 0.9us */ | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| static const rmt_symbol_word_t ws2812_one = { | ||||||||||||||||||||||||||
| .level0 = 1, | ||||||||||||||||||||||||||
| .duration0 = 9, /*!< 0.9us */ | ||||||||||||||||||||||||||
| .level1 = 0, | ||||||||||||||||||||||||||
| .duration1 = 3, /*!< 0.4us */ | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
Comment on lines
+17
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Fix WS2812 ‘1’ timing and comment mismatch; keep a consistent bit period. At 10 MHz resolution, duration1 = 3 equals 0.3 µs but the comment says 0.4 µs. Also the resulting ‘1’ period (0.9 + 0.3 = 1.2 µs) differs from the ‘0’ period (0.4 + 0.9 = 1.3 µs). Using 9 + 4 keeps both at ~1.3 µs and matches the comment. static const rmt_symbol_word_t ws2812_one = {
.level0 = 1,
.duration0 = 9, /*!< 0.9us */
.level1 = 0,
- .duration1 = 3, /*!< 0.4us */
+ .duration1 = 4, /*!< 0.4us */
};📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| static const rmt_symbol_word_t ws2812_reset = { | ||||||||||||||||||||||||||
| .level0 = 0, | ||||||||||||||||||||||||||
| .duration0 = 250, /*!< 25us */ | ||||||||||||||||||||||||||
| .level1 = 0, | ||||||||||||||||||||||||||
| .duration1 = 250, /*!< 25us */ | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| static size_t encoder_callback(const void *data, size_t data_size, | ||||||||||||||||||||||||||
| size_t symbols_written, size_t symbols_free, | ||||||||||||||||||||||||||
| rmt_symbol_word_t *symbols, bool *done, void *arg) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| if (symbols_free < 8) { | ||||||||||||||||||||||||||
| return 0; /*!< Need at least 8 symbols to form one byte */ | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| printf("symbols_written:%d,data_size:%d\n", symbols_written, data_size); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
Comment on lines
+35
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Format string bug: use %zu for size_t or switch to ESP_LOGx. Using %d for size_t is undefined behavior on some platforms. Switch to %zu (or cast) and, ideally, use ESP_LOGD to control log verbosity. - printf("symbols_written:%d,data_size:%d\n", symbols_written, data_size);
+ ESP_LOGD(TAG, "symbols_written:%zu, data_size:%zu", symbols_written, data_size);If you prefer printf, use: - printf("symbols_written:%d,data_size:%d\n", symbols_written, data_size);
+ printf("symbols_written:%zu,data_size:%zu\n", symbols_written, data_size);🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| size_t data_pos = symbols_written / 8; /*!< Calculate current byte position, assuming input is {0xFF, 0x00, 0x00}, data_size is 3, each byte written increments symbols_written by 8 */ | ||||||||||||||||||||||||||
| uint8_t *data_bytes = (uint8_t *)data; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if (data_pos < data_size) { | ||||||||||||||||||||||||||
| size_t symbol_pos = 0; | ||||||||||||||||||||||||||
| for (int bitmask = 0x80; bitmask != 0; bitmask >>= 1) { | ||||||||||||||||||||||||||
| if (data_bytes[data_pos] & bitmask) { | ||||||||||||||||||||||||||
| symbols[symbol_pos++] = ws2812_one; | ||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||
| symbols[symbol_pos++] = ws2812_zero; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return symbol_pos; | ||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||
| symbols[0] = ws2812_reset; | ||||||||||||||||||||||||||
| *done = 1; | ||||||||||||||||||||||||||
| return 1; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| void app_main(void) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| rmt_channel_handle_t led_chan = NULL; | ||||||||||||||||||||||||||
| rmt_tx_channel_config_t tx_chan_config = { | ||||||||||||||||||||||||||
| .mem_block_symbols = 64, | ||||||||||||||||||||||||||
| .clk_src = RMT_CLK_SRC_DEFAULT, | ||||||||||||||||||||||||||
| .resolution_hz = 10 * 1000 * 1000, // 10MHz, 1 tick = 0.1us | ||||||||||||||||||||||||||
| .trans_queue_depth = 4, | ||||||||||||||||||||||||||
| .gpio_num = GPIO_NUM_38, | ||||||||||||||||||||||||||
| .intr_priority = 3 | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan)); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ESP_LOGI(TAG, "Create simple callback-based encoder"); | ||||||||||||||||||||||||||
| rmt_encoder_handle_t simple_encoder = NULL; | ||||||||||||||||||||||||||
| const rmt_simple_encoder_config_t simple_encoder_cfg = { | ||||||||||||||||||||||||||
| .callback = encoder_callback | ||||||||||||||||||||||||||
| // Note we don't set min_chunk_size here as the default of 64 is good enough. | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
| ESP_ERROR_CHECK(rmt_new_simple_encoder(&simple_encoder_cfg, &simple_encoder)); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ESP_LOGI(TAG, "Enable RMT TX channel"); | ||||||||||||||||||||||||||
| ESP_ERROR_CHECK(rmt_enable(led_chan)); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
Comment on lines
+73
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Wrap RMT calls with ESP_ERROR_CHECK and optionally wait for completion. Keeps the example robust and makes failures obvious during bring-up. ESP_LOGI(TAG, "Create simple callback-based encoder");
rmt_encoder_handle_t simple_encoder = NULL;
@@
- ESP_ERROR_CHECK(rmt_new_simple_encoder(&simple_encoder_cfg, &simple_encoder));
+ ESP_ERROR_CHECK(rmt_new_simple_encoder(&simple_encoder_cfg, &simple_encoder));
@@
- rmt_transmit(led_chan, simple_encoder, red, sizeof(red), &tx_config);
+ ESP_ERROR_CHECK(rmt_transmit(led_chan, simple_encoder, red, sizeof(red), &tx_config));
+ ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));
vTaskDelay(1000 / portTICK_PERIOD_MS);
@@
- rmt_transmit(led_chan, simple_encoder, green, sizeof(green), &tx_config);
+ ESP_ERROR_CHECK(rmt_transmit(led_chan, simple_encoder, green, sizeof(green), &tx_config));
+ ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));
vTaskDelay(1000 / portTICK_PERIOD_MS);
@@
- rmt_transmit(led_chan, simple_encoder, blue, sizeof(blue), &tx_config);
+ ESP_ERROR_CHECK(rmt_transmit(led_chan, simple_encoder, blue, sizeof(blue), &tx_config));
+ ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));Also applies to: 91-101 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| ESP_LOGI(TAG, "Start LED rainbow chase"); | ||||||||||||||||||||||||||
| rmt_transmit_config_t tx_config = { | ||||||||||||||||||||||||||
| .loop_count = 0, // no transfer loop | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // WS2812 encoding is GRB | ||||||||||||||||||||||||||
| uint8_t red[3] = {0x00, 0xFF, 0x00}; /*!< R */ | ||||||||||||||||||||||||||
| rmt_transmit(led_chan, simple_encoder, red, sizeof(red), &tx_config); | ||||||||||||||||||||||||||
| vTaskDelay(1000 / portTICK_PERIOD_MS); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| uint8_t green[3] = {0xFF, 0x00, 0x00}; /*!< G */ | ||||||||||||||||||||||||||
| rmt_transmit(led_chan, simple_encoder, green, sizeof(green), &tx_config); | ||||||||||||||||||||||||||
| vTaskDelay(1000 / portTICK_PERIOD_MS); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| uint8_t blue[3] = {0x00, 0x00, 0xFF}; /*!< B */ | ||||||||||||||||||||||||||
| rmt_transmit(led_chan, simple_encoder, blue, sizeof(blue), &tx_config); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| CONFIG_IDF_TARGET="esp32s3" | ||
| CONFIG_IDF_TARGET_ESP32S3=y | ||
|
|
||
| CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y |
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.
💡 Verification agent
🧩 Analysis chain
Sanity-check component wiring across both new examples.
Ensure the same dependency pattern (PRIV_REQUIRES driver) is applied to the WS2812 example’s main component CMake as well, since it also uses RMT.
Run this script to verify component registration and basic RMT usage in sources:
🏁 Script executed:
Length of output: 297
🏁 Script executed:
Length of output: 8334
Apply RMT driver dependency to the WS2812 example’s main component
The WS2812 example’s
main/CMakeLists.txtcurrently omits the driver dependency even though it includes and uses the RMT API. Update it to match the pattern used for RMT-based examples:• File:
examples/peripherals/rmt/ws2812_simple_encoder/main/CMakeLists.txtidf_component_register(SRCS "main.c" INCLUDE_DIRS "." + PRIV_REQUIRES driver)For consistency, you may also add the same line to:
•
examples/peripherals/rmt/rmt_simple_tx/main/CMakeLists.txt(optional)📝 Committable suggestion
🤖 Prompt for AI Agents