From a483f0a8dcb36716454f5a3159d84b298a79d0d3 Mon Sep 17 00:00:00 2001 From: Juan Jose Carranza Garcia Date: Sun, 3 Dec 2023 14:42:24 -0600 Subject: [PATCH 1/3] Include pico_tone library as part rp2_common --- src/rp2_common/CMakeLists.txt | 1 + src/rp2_common/pico_tone/CMakeLists.txt | 11 ++++ src/rp2_common/pico_tone/include/pico/tone.h | 59 ++++++++++++++++++++ src/rp2_common/pico_tone/tone.c | 38 +++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 src/rp2_common/pico_tone/CMakeLists.txt create mode 100644 src/rp2_common/pico_tone/include/pico/tone.h create mode 100644 src/rp2_common/pico_tone/tone.c diff --git a/src/rp2_common/CMakeLists.txt b/src/rp2_common/CMakeLists.txt index 82f56f8c5..0548bf778 100644 --- a/src/rp2_common/CMakeLists.txt +++ b/src/rp2_common/CMakeLists.txt @@ -77,6 +77,7 @@ if (NOT PICO_BARE_METAL) pico_add_subdirectory(pico_fix) pico_add_subdirectory(pico_runtime) + pico_add_subdirectory(pico_tone) endif() diff --git a/src/rp2_common/pico_tone/CMakeLists.txt b/src/rp2_common/pico_tone/CMakeLists.txt new file mode 100644 index 000000000..0adb5ddf4 --- /dev/null +++ b/src/rp2_common/pico_tone/CMakeLists.txt @@ -0,0 +1,11 @@ +if (NOT TARGET pico_tone) + pico_add_library(pico_tone) + + target_include_directories(pico_tone_headers INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/include) + + target_sources(pico_tone INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/tone.c) + + target_link_libraries(pico_tone INTERFACE hardware_pwm) +endif() diff --git a/src/rp2_common/pico_tone/include/pico/tone.h b/src/rp2_common/pico_tone/include/pico/tone.h new file mode 100644 index 000000000..f8b66e9d0 --- /dev/null +++ b/src/rp2_common/pico_tone/include/pico/tone.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _PICO_TONE_H +#define _PICO_TONE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file tone.h + * \defgroup pico_tone pico_tone + * Adds support for playing tones using PWM. + * + */ + +// PICO_TONE_SILENCE_DELAY_MS, Default delay between tones in milliseconds +#ifndef PICO_TONE_SILENCE_DELAY_MS +#define PICO_TONE_SILENCE_DELAY_MS 10U +#endif + +/*! \brief Initialise the tone generator + * \ingroup pico_tone + * + * Initilise PWM on the given GPIO using the default pwm config. + * + * \param gpio The GPIO to use for the tone generator + */ +void tone_init(uint gpio); + +/*! \brief Play a tone for a given duration + * \ingroup pico_tone + * + * Play a tone on the given GPIO for the given duration. + * + * \param gpio The GPIO to use for the tone generator + * \param freq The frequency of the tone in Hz + * \param duration_ms The duration of the tone in milliseconds + */ +void tone(uint gpio, uint freq, float duration_ms); + +/*! \brief Do not play any tone. + * \ingroup pico_tone + * + * Stop playing a tone on the given GPIO. + * + * \param gpio The GPIO to use for the tone generator + */ +void no_tone(uint gpio); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/rp2_common/pico_tone/tone.c b/src/rp2_common/pico_tone/tone.c new file mode 100644 index 000000000..1dc9b6e18 --- /dev/null +++ b/src/rp2_common/pico_tone/tone.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "pico/stdlib.h" +#include "pico/tone.h" +#include "hardware/pwm.h" + +void tone_init(uint gpio) { + // Configure GPIO for PWM output + gpio_set_function(gpio, GPIO_FUNC_PWM); + // Find out which PWM slice is connected to GPIO + uint slice_num = pwm_gpio_to_slice_num(gpio); + // Get default configuration for PWM slice and initialise PWM with it + pwm_config config = pwm_get_default_config(); + pwm_init(slice_num, &config, true); +} + +void no_tone(uint gpio) { + pwm_set_gpio_level(gpio, 0); +} + +void tone(uint gpio, uint freq, float duration_ms) { + // Calculate and cofigure new clock divider according to the frequency + // This formula is assuming we are running at 125MHz. + // TODO: Make this work for any frequency + float clkdiv = (1.f / freq) * 2000.f; + uint slice_num = pwm_gpio_to_slice_num(gpio); + pwm_set_clkdiv(slice_num, clkdiv); + // Configure duty to 50% ((2**16)-1)/2) to generate a square wave + pwm_set_gpio_level(gpio, 32768U); + sleep_ms(duration_ms); + + // Make silence for some ms to distinguish between tones + no_tone(gpio); + sleep_ms(PICO_TONE_SILENCE_DELAY_MS); +} From 84f49a00474b5b509c5a652cbffa1af0f39edcc3 Mon Sep 17 00:00:00 2001 From: Juan Jose Carranza Garcia Date: Sun, 3 Dec 2023 15:06:29 -0600 Subject: [PATCH 2/3] Include documentation for tone generation --- src/rp2_common/pico_tone/include/pico/tone.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/rp2_common/pico_tone/include/pico/tone.h b/src/rp2_common/pico_tone/include/pico/tone.h index f8b66e9d0..ebb5c1041 100644 --- a/src/rp2_common/pico_tone/include/pico/tone.h +++ b/src/rp2_common/pico_tone/include/pico/tone.h @@ -13,8 +13,19 @@ extern "C" { /** \file tone.h * \defgroup pico_tone pico_tone - * Adds support for playing tones using PWM. + * + * Adds support for playing tones using PWM. * + * Every sound humans encounter consists of one or more frequencies, and the + * way the ear interprets those sounds is called pitch. + * + * In order to produce a variety of pitches, a digital signal needs to convey + * the frequency of sound it is trying to reproduce. The simplest approach is + * to generate a 50% duty cycle pulse stream and set the frequency to the + * desired pitch. + * + * References: + * - https://www.hackster.io/106958/pwm-sound-synthesis-9596f0#overview */ // PICO_TONE_SILENCE_DELAY_MS, Default delay between tones in milliseconds From c6fccb7cce67f7d267e6b78d5e9c9947b6c0c171 Mon Sep 17 00:00:00 2001 From: Juan Jose Carranza Garcia Date: Sun, 3 Dec 2023 15:48:21 -0600 Subject: [PATCH 3/3] Duration should be uint32_t, not float --- src/rp2_common/pico_tone/include/pico/tone.h | 2 +- src/rp2_common/pico_tone/tone.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rp2_common/pico_tone/include/pico/tone.h b/src/rp2_common/pico_tone/include/pico/tone.h index ebb5c1041..b53762e19 100644 --- a/src/rp2_common/pico_tone/include/pico/tone.h +++ b/src/rp2_common/pico_tone/include/pico/tone.h @@ -51,7 +51,7 @@ void tone_init(uint gpio); * \param freq The frequency of the tone in Hz * \param duration_ms The duration of the tone in milliseconds */ -void tone(uint gpio, uint freq, float duration_ms); +void tone(uint gpio, uint freq, uint32_t duration_ms); /*! \brief Do not play any tone. * \ingroup pico_tone diff --git a/src/rp2_common/pico_tone/tone.c b/src/rp2_common/pico_tone/tone.c index 1dc9b6e18..9696c04cd 100644 --- a/src/rp2_common/pico_tone/tone.c +++ b/src/rp2_common/pico_tone/tone.c @@ -21,7 +21,7 @@ void no_tone(uint gpio) { pwm_set_gpio_level(gpio, 0); } -void tone(uint gpio, uint freq, float duration_ms) { +void tone(uint gpio, uint freq, uint32_t duration_ms) { // Calculate and cofigure new clock divider according to the frequency // This formula is assuming we are running at 125MHz. // TODO: Make this work for any frequency