mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-09 23:54:33 +02:00
example: update musical buzzer example with new rmt driver
This commit is contained in:
@@ -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)
|
@@ -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.
|
@@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "morse_code_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -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
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
||||
|
@@ -1,5 +0,0 @@
|
||||
set(component_srcs "src/musical_buzzer_rmt.c")
|
||||
|
||||
idf_component_register(SRCS "${component_srcs}"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_REQUIRES driver)
|
@@ -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
|
@@ -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, ¬ation_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, ¬ation_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,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 ".")
|
||||
|
@@ -1,25 +1,22 @@
|
||||
/* RMT example -- Musical Buzzer
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
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 "esp_log.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "musical_buzzer.h"
|
||||
#include "driver/rmt_tx.h"
|
||||
#include "musical_score_encoder.h"
|
||||
|
||||
#define RMT_BUZZER_RESOLUTION_HZ 1000000 // 1MHz resolution
|
||||
#define RMT_BUZZER_GPIO_NUM 0
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
#define RMT_TX_CHANNEL RMT_CHANNEL_0
|
||||
#define RMT_TX_GPIO_NUM (4)
|
||||
|
||||
/**
|
||||
* @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
|
||||
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));
|
||||
|
||||
// Install RMT driver
|
||||
ESP_ERROR_CHECK(rmt_config(&dev_config));
|
||||
ESP_ERROR_CHECK(rmt_driver_install(RMT_TX_CHANNEL, 0, 0));
|
||||
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));
|
||||
|
||||
// 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, "Enable RMT TX channel");
|
||||
ESP_ERROR_CHECK(rmt_enable(buzzer_chan));
|
||||
ESP_LOGI(TAG, "Playing Beethoven's Ode to joy...");
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@@ -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(©_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;
|
||||
}
|
@@ -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
|
@@ -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")
|
@@ -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
|
||||
|
Reference in New Issue
Block a user