mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 20:24:32 +02:00
Merge branch 'feature/musical_buzzer' into 'master'
RMT example: musical buzzer See merge request espressif/esp-idf!10346
This commit is contained in:
@@ -859,6 +859,19 @@ esp_err_t rmt_add_channel_to_group(rmt_channel_t channel);
|
||||
esp_err_t rmt_remove_channel_from_group(rmt_channel_t channel);
|
||||
#endif
|
||||
|
||||
#if SOC_RMT_SUPPORT_TX_LOOP_COUNT
|
||||
/**
|
||||
* @brief Set loop count for RMT TX channel
|
||||
*
|
||||
* @param channel RMT channel
|
||||
* @param count loop count
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_tx_loop_count(rmt_channel_t channel, uint32_t count);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reset RMT TX/RX memory index.
|
||||
*
|
||||
|
@@ -1365,3 +1365,14 @@ esp_err_t rmt_memory_rw_rst(rmt_channel_t channel)
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_RMT_SUPPORT_TX_LOOP_COUNT
|
||||
esp_err_t rmt_set_tx_loop_count(rmt_channel_t channel, uint32_t count)
|
||||
{
|
||||
RMT_CHECK(RMT_IS_TX_CHANNEL(channel), RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_ENTER_CRITICAL();
|
||||
rmt_ll_tx_set_loop_count(rmt_contex.hal.regs, channel, count);
|
||||
RMT_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
@@ -293,9 +293,10 @@ If the RMT driver has been installed with :cpp:func:`rmt_driver_install` for som
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
* A simple RMT TX example: :example:`peripherals/rmt/morse_code`.
|
||||
* Another RMT TX example, specific to drive a common RGB LED strip: :example:`peripherals/rmt/led_strip`.
|
||||
* Using RMT to send morse code: :example:`peripherals/rmt/morse_code`.
|
||||
* Using RMT to drive RGB LED strip: :example:`peripherals/rmt/led_strip`.
|
||||
* NEC remote control TX and RX example: :example:`peripherals/rmt/ir_protocols`.
|
||||
* Musical buzzer example: :example:`peripherals/rmt/musical_buzzer`.
|
||||
|
||||
|
||||
API Reference
|
||||
|
@@ -67,7 +67,7 @@ static void rmt_tx_init(void)
|
||||
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
|
||||
}
|
||||
|
||||
void app_main(void *ignore)
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Configuring transmitter");
|
||||
rmt_tx_init();
|
||||
|
6
examples/peripherals/rmt/musical_buzzer/CMakeLists.txt
Normal file
6
examples/peripherals/rmt/musical_buzzer/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# 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(musical_buzzer)
|
58
examples/peripherals/rmt/musical_buzzer/README.md
Normal file
58
examples/peripherals/rmt/musical_buzzer/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
| Supported Targets | ESP32-S2 | ESP32-C3 |
|
||||
| ----------------- | -------- | -------- |
|
||||
|
||||
# RMT Transmit Loop 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.
|
||||
|
||||
This example will show how to drive a passive buzzer to play a simple music, based on the RMT loop feature.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with ESP32-S2 SoC
|
||||
* A USB cable for Power supply and programming
|
||||
* A passive buzzer
|
||||
|
||||
Connection :
|
||||
|
||||
```
|
||||
VCC +--------------+
|
||||
| /+
|
||||
+++ |
|
||||
| | | Passive Buzzer
|
||||
+++ |
|
||||
| \+
|
||||
|
|
||||
+ |
|
||||
+<----+
|
||||
GPIO +--------+
|
||||
+-----+
|
||||
+ |
|
||||
|
|
||||
GND +--------------+
|
||||
```
|
||||
|
||||
### 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](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
|
||||
|
||||
```
|
||||
I (325) 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`.
|
||||
|
||||
## 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,0 +1,7 @@
|
||||
set(component_srcs "src/musical_buzzer_rmt.c")
|
||||
|
||||
idf_component_register(SRCS "${component_srcs}"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS ""
|
||||
PRIV_REQUIRES "driver"
|
||||
REQUIRES "")
|
@@ -0,0 +1,108 @@
|
||||
// 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,0 +1,135 @@
|
||||
// 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;
|
||||
}
|
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "musical_buzzer_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -0,0 +1,63 @@
|
||||
/* RMT example -- Musical Buzzer
|
||||
|
||||
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"
|
||||
|
||||
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
|
||||
*
|
||||
*/
|
||||
static const musical_buzzer_notation_t notation[] = {
|
||||
{740, 400}, {740, 600}, {784, 400}, {880, 400},
|
||||
{880, 400}, {784, 400}, {740, 400}, {659, 400},
|
||||
{587, 400}, {587, 400}, {659, 400}, {740, 400},
|
||||
{740, 400}, {740, 200}, {659, 200}, {659, 800},
|
||||
|
||||
{740, 400}, {740, 600}, {784, 400}, {880, 400},
|
||||
{880, 400}, {784, 400}, {740, 400}, {659, 400},
|
||||
{587, 400}, {587, 400}, {659, 400}, {740, 400},
|
||||
{659, 400}, {659, 200}, {587, 200}, {587, 800},
|
||||
|
||||
{659, 400}, {659, 400}, {740, 400}, {587, 400},
|
||||
{659, 400}, {740, 200}, {784, 200}, {740, 400}, {587, 400},
|
||||
{659, 400}, {740, 200}, {784, 200}, {740, 400}, {659, 400},
|
||||
{587, 400}, {659, 400}, {440, 400}, {440, 400},
|
||||
|
||||
{740, 400}, {740, 600}, {784, 400}, {880, 400},
|
||||
{880, 400}, {784, 400}, {740, 400}, {659, 400},
|
||||
{587, 400}, {587, 400}, {659, 400}, {740, 400},
|
||||
{659, 400}, {659, 200}, {587, 200}, {587, 800},
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
// 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, "Playing Beethoven's Ode to joy");
|
||||
|
||||
ESP_ERROR_CHECK(buzzer->play(buzzer, notation, sizeof(notation) / sizeof(notation[0])));
|
||||
}
|
Reference in New Issue
Block a user