Ver Fonte

example: update musical buzzer example with new rmt driver

morris há 3 anos atrás
pai
commit
b3c1480d9c

+ 0 - 6
examples/peripherals/rmt/morse_code/CMakeLists.txt

@@ -1,6 +0,0 @@
-# The following 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.5)
-
-include($ENV{IDF_PATH}/tools/cmake/project.cmake)
-project(morse_code)

+ 0 - 66
examples/peripherals/rmt/morse_code/README.md

@@ -1,66 +0,0 @@
-# RMT Transmit Example -- Morse Code
-
-(See the README.md file in the upper level 'examples' directory for more information about examples.)
-
-This example mainly illustrates how to transmit the [Morse code](https://en.wikipedia.org/wiki/Morse_code) using the RMT driver.
-
-## How to Use Example
-
-### Hardware Required
-
-* A development board with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
-* A USB cable for Power supply and programming
-* A LED, a speaker or an earphone
-
-Connection :
-
-```
-             330R            LED     
-GPIO18 +----/\/\/\----+------|>|-----+ GND
-                      |    
-                      | /|
-                     +-+ |   Speaker
-                     | | |     or
-                     +-+ |  earphone
-                      | \|
-                      |
-                      +--------------+ GND
-```
-
-### Configure the Project
-
-Open the project configuration menu (`idf.py menuconfig`). 
-
-In the `Example Configuration` menu:
-
-* Set the GPIO number used for transmitting the IR signal under `RMT TX GPIO` optin.
-
-### Build and Flash
-
-Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
-
-(To exit the serial monitor, type ``Ctrl-]``.)
-
-See the Getting Started Guide for all the steps to configure and use the ESP-IDF to build projects.
-
-* [ESP-IDF Getting Started Guide on ESP32](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html)
-* [ESP-IDF Getting Started Guide on ESP32-S2](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
-* [ESP-IDF Getting Started Guide on ESP32-C3](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/get-started/index.html)
-
-
-## Example Output
-
-To be able to see and hear the message output by the RMT, connect an LED and a speaker or an earphone (be careful it might make a large noise) to the GPIO you set in the menuconfig.
-
-Run the example, you will see the following output log:
-
-``` bash
-...
-I (304) example: Configuring transmitter
-I (2814) example: Transmission complete
-...
-```
-
-## Troubleshooting
-
-For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

+ 0 - 2
examples/peripherals/rmt/morse_code/main/CMakeLists.txt

@@ -1,2 +0,0 @@
-idf_component_register(SRCS "morse_code_main.c"
-                       INCLUDE_DIRS ".")

+ 0 - 7
examples/peripherals/rmt/morse_code/main/Kconfig.projbuild

@@ -1,7 +0,0 @@
-menu "Example Configuration"
-    config EXAMPLE_RMT_TX_GPIO
-        int "RMT TX GPIO"
-        default 18
-        help
-            Set the GPIO number used for transmitting the RMT signal.
-endmenu

+ 0 - 80
examples/peripherals/rmt/morse_code/main/morse_code_main.c

@@ -1,80 +0,0 @@
-/* RMT example -- Morse Code
-
-   This example code is in the Public Domain (or CC0 licensed, at your option.)
-
-   Unless required by applicable law or agreed to in writing, this
-   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-   CONDITIONS OF ANY KIND, either express or implied.
-*/
-#include "sdkconfig.h"
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include "esp_log.h"
-#include "driver/rmt.h"
-
-static const char *TAG = "example";
-
-#define RMT_TX_CHANNEL RMT_CHANNEL_0
-
-/*
- * Prepare a raw table with a message in the Morse code
- *
- * The message is "ESP" : . ... .--.
- *
- * The table structure represents the RMT item structure:
- * {duration, level, duration, level}
- *
- */
-static const rmt_item32_t morse_esp[] = {
-    // E : dot
-    {{{ 32767, 1, 32767, 0 }}}, // dot
-    {{{ 32767, 0, 32767, 0 }}}, // SPACE
-    // S : dot, dot, dot
-    {{{ 32767, 1, 32767, 0 }}}, // dot
-    {{{ 32767, 1, 32767, 0 }}}, // dot
-    {{{ 32767, 1, 32767, 0 }}}, // dot
-    {{{ 32767, 0, 32767, 0 }}}, // SPACE
-    // P : dot, dash, dash, dot
-    {{{ 32767, 1, 32767, 0 }}}, // dot
-    {{{ 32767, 1, 32767, 1 }}},
-    {{{ 32767, 1, 32767, 0 }}}, // dash
-    {{{ 32767, 1, 32767, 1 }}},
-    {{{ 32767, 1, 32767, 0 }}}, // dash
-    {{{ 32767, 1, 32767, 0 }}}, // dot
-    // RMT end marker
-    {{{ 0, 1, 0, 0 }}}
-};
-
-/*
- * Initialize the RMT Tx channel
- */
-static void rmt_tx_init(void)
-{
-    rmt_config_t config = RMT_DEFAULT_CONFIG_TX(CONFIG_EXAMPLE_RMT_TX_GPIO, RMT_TX_CHANNEL);
-    // enable the carrier to be able to hear the Morse sound
-    // if the RMT_TX_GPIO is connected to a speaker
-    config.tx_config.carrier_en = true;
-    config.tx_config.carrier_duty_percent = 50;
-    // set audible career frequency of 611 Hz
-    // actually 611 Hz is the minimum, that can be set
-    // with current implementation of the RMT API
-    config.tx_config.carrier_freq_hz = 611;
-    // set the maximum clock divider to be able to output
-    // RMT pulses in range of about one hundred milliseconds
-    config.clk_div = 255;
-
-    ESP_ERROR_CHECK(rmt_config(&config));
-    ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
-}
-
-void app_main(void)
-{
-    ESP_LOGI(TAG, "Configuring transmitter");
-    rmt_tx_init();
-
-    while (1) {
-        ESP_ERROR_CHECK(rmt_write_items(RMT_TX_CHANNEL, morse_esp, sizeof(morse_esp) / sizeof(morse_esp[0]), true));
-        ESP_LOGI(TAG, "Transmission complete");
-        vTaskDelay(1000 / portTICK_PERIOD_MS);
-    }
-}

+ 31 - 24
examples/peripherals/rmt/musical_buzzer/README.md

@@ -1,41 +1,43 @@
-| Supported Targets | ESP32-S2 | ESP32-C3 |
-| ----------------- | -------- | -------- |
+| Supported Targets | ESP32-S2 | ESP32-C3 | ESP32-S3 |
+| ----------------- | -------- | -------- | -------- |
 
-# RMT Transmit Loop Example -- Musical Buzzer
+# RMT Transmit Loop Count Example -- Musical Buzzer
 
 (See the README.md file in the upper level 'examples' directory for more information about examples.)
 
-RMT peripheral can send customized RMT items in a loop, which means we can use it to generate a configurable length of periodic signal.
+RMT tx channel can send symbols in a loop by hardware, which is useful to generate a variable length of periodic signal.
 
-This example will show how to drive a passive buzzer to play a simple music, based on the RMT loop feature.
+This example shows how to drive a passive buzzer to play a simple music. Each musical score is represented by a constant frequency of PWM with a constant duration. To play a music is to encoding the musical score continuously. An encoder called `score_encoder` is implemented in the example, it works as a simple wrapper of the `copy_encoder`. See [musical_score_encoder](main/musical_score_encoder.c) for details.
 
 ## How to Use Example
 
 ### Hardware Required
 
-* A development board with ESP32-S2 SoC
+* A development board with any supported Espressif SOC chip (see `Supported Targets` table above)
 * A USB cable for Power supply and programming
-* A passive buzzer
+* A **passive** buzzer
 
 Connection :
 
 ```
-VCC  +--------------+
-                    | /+
-                   +++ |
-                   | | | Passive Buzzer
-                   +++ |
-                    | \+
-                    |
-              +     |
-              +<----+
-GPIO +--------+
-              +-----+
-              +     |
-                    |
-GND  +--------------+
+            VCC+--------------+
+                              | /+
+                             +++ |
+                             | | | Passive Buzzer
+                             +++ |
+                              | \+
+                              |
+                        +     |
+                        +<----+
+RMT_BUZZER_GPIO+--------+
+                        +-----+
+                        +     |
+                              |
+            GND+--------------+
 ```
 
+The GPIO number used in this example can be changed according to your board, by the macro `RMT_BUZZER_GPIO_NUM` defined in the [source file](main/musical_buzzer_example_main.c).
+
 ### Build and Flash
 
 Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
@@ -45,13 +47,18 @@ Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
 See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
 
 
-## Example Output
+## Console Output
 
 ```
-I (325) example: Playing Beethoven's Ode to joy
+...
+I (0) cpu_start: Starting scheduler on APP CPU.
+I (318) example: Create RMT TX channel
+I (338) example: Install musical score encoder
+I (348) example: Playing Beethoven's Ode to joy...
+...
 ```
 
-After you seeing this log, you should hear the music from your buzzer. You can also play other music by updating the `notation` array in the `musical_buzzer_example_main.c`.
+After you seeing this log, you should hear the music from the buzzer. To play other music, you need to change the musical score array `score` defined in the [source file](main/musical_buzzer_example_main.c). The first member declares the frequency of one musical note, and the second member declares the duration that the note should last.
 
 ## Troubleshooting
 

+ 0 - 5
examples/peripherals/rmt/musical_buzzer/components/musical_buzzer/CMakeLists.txt

@@ -1,5 +0,0 @@
-set(component_srcs "src/musical_buzzer_rmt.c")
-
-idf_component_register(SRCS "${component_srcs}"
-                       INCLUDE_DIRS include
-                       PRIV_REQUIRES driver)

+ 0 - 108
examples/peripherals/rmt/musical_buzzer/components/musical_buzzer/include/musical_buzzer.h

@@ -1,108 +0,0 @@
-// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#pragma once
-
-#include "esp_err.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief Type of musical buzzer interface
- *
- */
-typedef struct musical_buzzer_t musical_buzzer_t;
-
-/**
- * @brief Type of musical buzzer underlying device
- *
- */
-typedef void *musical_buzzer_dev_t;
-
-/**
- * @brief Type of musical buzzer notation
- *
- */
-typedef struct {
-    uint32_t note_freq_hz;     /*!< Note frequency, in Hz */
-    uint32_t note_duration_ms; /*!< Note duration, in ms */
-} musical_buzzer_notation_t;
-
-/**
- * @brief Declaration of musical buzzer interface
- *
- */
-struct musical_buzzer_t {
-    /**
-    * @brief Start to play the given notation
-    *
-    * @param buzzer musical buzzer handle
-    * @param notation music notation
-    * @param notation_len notation length
-    * @return
-    *      - ESP_OK: Start playing notation successfully
-    *      - ESP_ERR_INVALID_ARG: wrong parameter
-    */
-    esp_err_t (*play)(musical_buzzer_t *buzzer, const musical_buzzer_notation_t *notation, uint32_t notation_len);
-
-    /**
-     * @brief Stop playing
-     *
-     * @param buzzer musical buzzer handle
-     * @return
-     *      - ESP_OK: Stop playing successfully
-     */
-    esp_err_t (*stop)(musical_buzzer_t *buzzer);
-
-    /**
-     * @brief Free memory used by musical buzzer
-     *
-     * @param buzzer musical buzzer handle
-     * @return
-     *      - ESP_OK: Recycle memory successfully
-     */
-    esp_err_t (*del)(musical_buzzer_t *buzzer);
-};
-
-typedef struct {
-    musical_buzzer_dev_t dev; /*!< Musical buzzer device (e.g. RMT channel, PWM channel, etc) */
-    int flags;                /*!< Extra flags */
-} musical_buzzer_config_t;
-
-/**
- * @brief Default musical buzzer configuration
- *
- */
-#define MUSICAL_BUZZER_DEFAULT_CONFIG(dev_hdl) \
-    {                                          \
-        .dev = dev_hdl,                        \
-        .flags = 0,                            \
-    }
-
-/**
- * @brief Create musical buzzer instance based on RMT driver
- *
- * @param config musical buzzer configuration
- * @param[out] ret_handle returned handle of musical buzzer instance
- * @return
- *      - ESP_OK: create musical buzzer instance successfully
- *      - ESP_ERR_INVALID_ARG: wrong parameter
- *      - ESP_ERR_NO_MEM: no memory to allocate instance
- */
-esp_err_t musical_buzzer_create_rmt(const musical_buzzer_config_t *config, musical_buzzer_t **ret_handle);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 135
examples/peripherals/rmt/musical_buzzer/components/musical_buzzer/src/musical_buzzer_rmt.c

@@ -1,135 +0,0 @@
-// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include "esp_log.h"
-#include "esp_attr.h"
-#include "esp_compiler.h"
-#include "driver/rmt.h"
-#include "musical_buzzer.h"
-
-static const char *TAG = "buzzer_rmt";
-
-#define BUZZER_CHECK(a, msg, tag, ret, ...)                                       \
-    do {                                                                          \
-        if (unlikely(!(a))) {                                                     \
-            ESP_LOGE(TAG, "%s(%d): " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
-            ret_code = ret;                                                       \
-            goto tag;                                                             \
-        }                                                                         \
-    } while (0)
-
-typedef struct {
-    musical_buzzer_t parent;
-    rmt_channel_t channel;
-    uint32_t counter_clk_hz;
-    const musical_buzzer_notation_t *notation;
-    uint32_t notation_length;
-    uint32_t next_notation_index;
-} rmt_buzzer_t;
-
-static IRAM_ATTR rmt_item32_t update_notation_freq_duration(rmt_buzzer_t *rmt_buzzer)
-{
-    rmt_item32_t notation_code = {.level0 = 1, .duration0 = 1, .level1 = 0, .duration1 = 1};
-    const musical_buzzer_notation_t *notation = &rmt_buzzer->notation[rmt_buzzer->next_notation_index];
-
-    // convert frequency to RMT item format
-    notation_code.duration0 = rmt_buzzer->counter_clk_hz / notation->note_freq_hz / 2;
-    notation_code.duration1 = notation_code.duration0;
-    // convert duration to RMT loop count
-    rmt_set_tx_loop_count(rmt_buzzer->channel, notation->note_duration_ms * notation->note_freq_hz / 1000);
-
-    rmt_buzzer->next_notation_index++;
-    return notation_code;
-}
-
-static esp_err_t buzzer_play(musical_buzzer_t *buzzer, const musical_buzzer_notation_t *notation, uint32_t notation_length)
-{
-    esp_err_t ret_code = ESP_OK;
-    rmt_buzzer_t *rmt_buzzer = __containerof(buzzer, rmt_buzzer_t, parent);
-
-    BUZZER_CHECK(notation, "notation can't be null", err, ESP_ERR_INVALID_ARG);
-
-    // update notation with the new one
-    rmt_buzzer->notation = notation;
-    rmt_buzzer->next_notation_index = 0;
-    rmt_buzzer->notation_length = notation_length;
-
-    rmt_item32_t notation_code = update_notation_freq_duration(rmt_buzzer);
-    // start TX
-    rmt_write_items(rmt_buzzer->channel, &notation_code, 1, false);
-err:
-    return ret_code;
-}
-
-static esp_err_t buzzer_stop(musical_buzzer_t *buzzer)
-{
-    rmt_buzzer_t *rmt_buzzer = __containerof(buzzer, rmt_buzzer_t, parent);
-    rmt_tx_stop(rmt_buzzer->channel);
-    return ESP_OK;
-}
-
-static esp_err_t buzzer_del(musical_buzzer_t *buzzer)
-{
-    rmt_buzzer_t *rmt_buzzer = __containerof(buzzer, rmt_buzzer_t, parent);
-    free(rmt_buzzer);
-    return ESP_OK;
-}
-
-static void rmt_tx_loop_end(rmt_channel_t channel, void *args)
-{
-    rmt_buzzer_t *rmt_buzzer = (rmt_buzzer_t *)args;
-
-    // stop it firstly, RMT TX engine won't stop automatically in loop mode
-    rmt_tx_stop(rmt_buzzer->channel);
-
-    // update rmt loop freq and duration if the notation doesn't reach the end
-    if (rmt_buzzer->next_notation_index < rmt_buzzer->notation_length) {
-        rmt_item32_t notation_code = update_notation_freq_duration(rmt_buzzer);
-        // issue a new TX transaction
-        rmt_write_items(rmt_buzzer->channel, &notation_code, 1, false);
-    }
-}
-
-esp_err_t musical_buzzer_create_rmt(const musical_buzzer_config_t *config, musical_buzzer_t **ret_handle)
-{
-    esp_err_t ret_code = ESP_OK;
-    rmt_buzzer_t *rmt_buzzer = NULL;
-    BUZZER_CHECK(config, "configuration can't be null", err, ESP_ERR_INVALID_ARG);
-    BUZZER_CHECK(ret_handle, "can't assign handle to null", err, ESP_ERR_INVALID_ARG);
-
-    rmt_buzzer = calloc(1, sizeof(rmt_buzzer_t));
-    BUZZER_CHECK(rmt_buzzer, "allocate context memory failed", err, ESP_ERR_NO_MEM);
-
-    rmt_buzzer->channel = (rmt_channel_t)config->dev;
-
-    rmt_get_counter_clock(rmt_buzzer->channel, &rmt_buzzer->counter_clk_hz);
-
-    // register tx end callback function, which got invoked when tx loop comes to the end
-    rmt_register_tx_end_callback(rmt_tx_loop_end, rmt_buzzer);
-
-    rmt_buzzer->parent.del = buzzer_del;
-    rmt_buzzer->parent.play = buzzer_play;
-    rmt_buzzer->parent.stop = buzzer_stop;
-
-    *ret_handle = &(rmt_buzzer->parent);
-    return ESP_OK;
-
-err:
-    if (rmt_buzzer) {
-        free(rmt_buzzer);
-    }
-    return ret_code;
-}

+ 1 - 2
examples/peripherals/rmt/musical_buzzer/main/CMakeLists.txt

@@ -1,3 +1,2 @@
-idf_component_register(SRCS "musical_buzzer_example_main.c"
-                       PRIV_REQUIRES musical_buzzer driver
+idf_component_register(SRCS "musical_buzzer_example_main.c" "musical_score_encoder.c"
                        INCLUDE_DIRS ".")

+ 37 - 29
examples/peripherals/rmt/musical_buzzer/main/musical_buzzer_example_main.c

@@ -1,25 +1,22 @@
-/* RMT example -- Musical Buzzer
-
-   This example code is in the Public Domain (or CC0 licensed, at your option.)
+/*
+ * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
 
-   Unless required by applicable law or agreed to in writing, this
-   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-   CONDITIONS OF ANY KIND, either express or implied.
-*/
 #include "esp_log.h"
-#include "driver/rmt.h"
-#include "musical_buzzer.h"
+#include "driver/rmt_tx.h"
+#include "musical_score_encoder.h"
 
-static const char *TAG = "example";
+#define RMT_BUZZER_RESOLUTION_HZ 1000000 // 1MHz resolution
+#define RMT_BUZZER_GPIO_NUM      0
 
-#define RMT_TX_CHANNEL RMT_CHANNEL_0
-#define RMT_TX_GPIO_NUM (4)
+static const char *TAG = "example";
 
 /**
- * @brief Musical Notation: Beethoven's Ode to joy
- *
+ * @brief Musical Score: Beethoven's Ode to joy
  */
-static const musical_buzzer_notation_t notation[] = {
+static const buzzer_musical_score_t score[] = {
     {740, 400}, {740, 600}, {784, 400}, {880, 400},
     {880, 400}, {784, 400}, {740, 400}, {659, 400},
     {587, 400}, {587, 400}, {659, 400}, {740, 400},
@@ -43,21 +40,32 @@ static const musical_buzzer_notation_t notation[] = {
 
 void app_main(void)
 {
-    // Apply default RMT configuration
-    rmt_config_t dev_config = RMT_DEFAULT_CONFIG_TX(RMT_TX_GPIO_NUM, RMT_TX_CHANNEL);
-    dev_config.tx_config.loop_en = true; // Enable loop mode
-
-    // Install RMT driver
-    ESP_ERROR_CHECK(rmt_config(&dev_config));
-    ESP_ERROR_CHECK(rmt_driver_install(RMT_TX_CHANNEL, 0, 0));
+    ESP_LOGI(TAG, "Create RMT TX channel");
+    rmt_channel_handle_t buzzer_chan = NULL;
+    rmt_tx_channel_config_t tx_chan_config = {
+        .clk_src = RMT_CLK_SRC_DEFAULT, // select source clock
+        .gpio_num = RMT_BUZZER_GPIO_NUM,
+        .mem_block_symbols = 64,
+        .resolution_hz = RMT_BUZZER_RESOLUTION_HZ,
+        .trans_queue_depth = 10, // set the maximum number of transactions that can pend in the background
+    };
+    ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &buzzer_chan));
 
-    // This example take the RMT channel number as the device handle
-    musical_buzzer_config_t buzzer_config = MUSICAL_BUZZER_DEFAULT_CONFIG((musical_buzzer_dev_t)RMT_TX_CHANNEL);
-    musical_buzzer_t *buzzer = NULL;
-    // Install buzzer driver
-    ESP_ERROR_CHECK(musical_buzzer_create_rmt(&buzzer_config, &buzzer));
+    ESP_LOGI(TAG, "Install musical score encoder");
+    rmt_encoder_handle_t score_encoder = NULL;
+    musical_score_encoder_config_t encoder_config = {
+        .resolution = RMT_BUZZER_RESOLUTION_HZ
+    };
+    ESP_ERROR_CHECK(rmt_new_musical_score_encoder(&encoder_config, &score_encoder));
 
-    ESP_LOGI(TAG, "Playing Beethoven's Ode to joy");
+    ESP_LOGI(TAG, "Enable RMT TX channel");
+    ESP_ERROR_CHECK(rmt_enable(buzzer_chan));
+    ESP_LOGI(TAG, "Playing Beethoven's Ode to joy...");
 
-    ESP_ERROR_CHECK(buzzer->play(buzzer, notation, sizeof(notation) / sizeof(notation[0])));
+    for (size_t i = 0; i < sizeof(score) / sizeof(score[0]); i++) {
+        rmt_transmit_config_t tx_config = {
+            .loop_count = score[i].duration_ms * score[i].freq_hz / 1000,
+        };
+        ESP_ERROR_CHECK(rmt_transmit(buzzer_chan, score_encoder, &score[i], sizeof(buzzer_musical_score_t), &tx_config));
+    }
 }

+ 74 - 0
examples/peripherals/rmt/musical_buzzer/main/musical_score_encoder.c

@@ -0,0 +1,74 @@
+/*
+ * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "esp_check.h"
+#include "musical_score_encoder.h"
+
+static const char *TAG = "score_encoder";
+
+typedef struct {
+    rmt_encoder_t base;
+    rmt_encoder_t *copy_encoder;
+    uint32_t resolution;
+} rmt_musical_score_encoder_t;
+
+static size_t rmt_encode_musical_score(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
+{
+    rmt_musical_score_encoder_t *score_encoder = __containerof(encoder, rmt_musical_score_encoder_t, base);
+    rmt_encoder_handle_t copy_encoder = score_encoder->copy_encoder;
+    rmt_encode_state_t session_state = 0;
+    buzzer_musical_score_t *score = (buzzer_musical_score_t *)primary_data;
+    uint32_t rmt_raw_symbol_duration = score_encoder->resolution / score->freq_hz / 2;
+    rmt_symbol_word_t musical_score_rmt_symbol = {
+        .level0 = 0,
+        .duration0 = rmt_raw_symbol_duration,
+        .level1 = 1,
+        .duration1 = rmt_raw_symbol_duration,
+    };
+    size_t encoded_symbols = copy_encoder->encode(copy_encoder, channel, &musical_score_rmt_symbol, sizeof(musical_score_rmt_symbol), &session_state);
+    *ret_state = session_state;
+    return encoded_symbols;
+}
+
+static esp_err_t rmt_del_musical_score_encoder(rmt_encoder_t *encoder)
+{
+    rmt_musical_score_encoder_t *score_encoder = __containerof(encoder, rmt_musical_score_encoder_t, base);
+    rmt_del_encoder(score_encoder->copy_encoder);
+    free(score_encoder);
+    return ESP_OK;
+}
+
+static esp_err_t rmt_musical_score_encoder_reset(rmt_encoder_t *encoder)
+{
+    rmt_musical_score_encoder_t *score_encoder = __containerof(encoder, rmt_musical_score_encoder_t, base);
+    rmt_encoder_reset(score_encoder->copy_encoder);
+    return ESP_OK;
+}
+
+esp_err_t rmt_new_musical_score_encoder(const musical_score_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
+{
+    esp_err_t ret = ESP_OK;
+    rmt_musical_score_encoder_t *score_encoder = NULL;
+    ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
+    score_encoder = calloc(1, sizeof(rmt_musical_score_encoder_t));
+    ESP_GOTO_ON_FALSE(score_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for musical score encoder");
+    score_encoder->base.encode = rmt_encode_musical_score;
+    score_encoder->base.del = rmt_del_musical_score_encoder;
+    score_encoder->base.reset = rmt_musical_score_encoder_reset;
+    score_encoder->resolution = config->resolution;
+    rmt_copy_encoder_config_t copy_encoder_config = {};
+    ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &score_encoder->copy_encoder), err, TAG, "create copy encoder failed");
+    *ret_encoder = &score_encoder->base;
+    return ESP_OK;
+err:
+    if (score_encoder) {
+        if (score_encoder->copy_encoder) {
+            rmt_del_encoder(score_encoder->copy_encoder);
+        }
+        free(score_encoder);
+    }
+    return ret;
+}

+ 44 - 0
examples/peripherals/rmt/musical_buzzer/main/musical_score_encoder.h

@@ -0,0 +1,44 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#pragma once
+
+#include <stdint.h>
+#include "driver/rmt_encoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Type of buzzer musical score
+ */
+typedef struct {
+    uint32_t freq_hz;     /*!< Frequency, in Hz */
+    uint32_t duration_ms; /*!< Duration, in ms */
+} buzzer_musical_score_t;
+
+/**
+ * @brief Type of musical score encoder configuration
+ */
+typedef struct {
+    uint32_t resolution; /*!< Encoder resolution, in Hz */
+} musical_score_encoder_config_t;
+
+/**
+ * @brief Create RMT encoder for encoding musical score into RMT symbols
+ *
+ * @param[in] config Encoder configuration
+ * @param[out] ret_encoder Returned encoder handle
+ * @return
+ *      - ESP_ERR_INVALID_ARG for any invalid arguments
+ *      - ESP_ERR_NO_MEM out of memory when creating musical score encoder
+ *      - ESP_OK if creating encoder successfully
+ */
+esp_err_t rmt_new_musical_score_encoder(const musical_score_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);
+
+#ifdef __cplusplus
+}
+#endif

+ 16 - 0
examples/peripherals/rmt/musical_buzzer/pytest_musical_buzzer.py

@@ -0,0 +1,16 @@
+# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
+# SPDX-License-Identifier: CC0-1.0
+
+import pytest
+from pytest_embedded import Dut
+
+
+@pytest.mark.esp32s2
+@pytest.mark.esp32s3
+@pytest.mark.esp32c3
+@pytest.mark.generic
+def test_musical_buzzer_example(dut: Dut) -> None:
+    dut.expect_exact('example: Create RMT TX channel')
+    dut.expect_exact('example: Install musical score encoder')
+    dut.expect_exact('example: Enable RMT TX channel')
+    dut.expect_exact("example: Playing Beethoven's Ode to joy")

+ 0 - 4
tools/ci/check_copyright_ignore.txt

@@ -2072,10 +2072,6 @@ examples/peripherals/mcpwm/mcpwm_brushed_dc_control/main/mcpwm_brushed_dc_contro
 examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/main/mcpwm_capture_hc_sr04.c
 examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example_main.c
 examples/peripherals/mcpwm/mcpwm_sync_example/main/mcpwm_sync_example.c
-examples/peripherals/rmt/morse_code/main/morse_code_main.c
-examples/peripherals/rmt/musical_buzzer/components/musical_buzzer/include/musical_buzzer.h
-examples/peripherals/rmt/musical_buzzer/components/musical_buzzer/src/musical_buzzer_rmt.c
-examples/peripherals/rmt/musical_buzzer/main/musical_buzzer_example_main.c
 examples/peripherals/sdio/host/main/app_main.c
 examples/peripherals/sdio/sdio_test.py
 examples/peripherals/sdio/slave/main/app_main.c