Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/rp2_common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ pico_add_subdirectory(pico_sd_card)
pico_add_subdirectory(pico_scanvideo_dpi)
pico_add_subdirectory(usb_common)
pico_add_subdirectory(usb_device)
pico_add_subdirectory(usb_device_msc)
pico_add_subdirectory(usb_device_msc)
pico_add_subdirectory(pico_tone)
11 changes: 11 additions & 0 deletions src/rp2_common/pico_tone/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
70 changes: 70 additions & 0 deletions src/rp2_common/pico_tone/include/pico/tone.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* 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.
*
* 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
#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, uint32_t 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
38 changes: 38 additions & 0 deletions src/rp2_common/pico_tone/tone.c
Original file line number Diff line number Diff line change
@@ -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, 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
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);
}