# https://www.fisheyecollaborative.org/fish-sounds/pempheris-schomburgkii $ ffmpeg -i pempheris.wav -f u8 -ar 22050 -ac 1 fishy.raw $ xxd -i fishy.raw > audio_data.h # CMakelist.txt cmake_minimum_required(VERSION 3.13) include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake) project(myapp C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) pico_sdk_init() add_executable(${PROJECT_NAME} main.c) pico_add_extra_outputs(${PROJECT_NAME}) # Link necessary libraries target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_pwm hardware_clocks ) pico_enable_stdio_usb(${PROJECT_NAME} 1) pico_enable_stdio_uart(${PROJECT_NAME} 0) # main.c //GPIO 16 → 100-470µF capacitor (+) → Speaker (+) //Speaker (-) → GND #include #include #include #include #include #define AUDIO_PIN 16 #define SAMPLE_RATE 22050 // Hz #define PWM_FREQ 100000 // PWM carrier frequency // Example audio data (replace with your PCM data) const uint8_t audio_data[] = { // example start on 128 (0): 128, 150, 170, 190, 210, 190, 170, 150, 128, 100, 80, 60, 40, 60, 80, 100 }; const uint32_t audio_data_len = sizeof(audio_data); // Playback state volatile uint32_t sample_index = 0; repeating_timer_t audio_timer; void init_pwm_audio(uint gpio) { gpio_set_function(gpio, GPIO_FUNC_PWM); uint slice = pwm_gpio_to_slice_num(gpio); pwm_config cfg = pwm_get_default_config(); float clk_hz = clock_get_hz(clk_sys); // Calculate divider for ~100kHz PWM carrier float div = clk_hz / (PWM_FREQ * 256.0f); pwm_config_set_clkdiv(&cfg, div); pwm_config_set_wrap(&cfg, 255); pwm_init(slice, &cfg, true); pwm_set_gpio_level(gpio, 128); } // Timer callback to update one sample bool audio_callback(repeating_timer_t *t) { if (sample_index >= audio_data_len) { pwm_set_gpio_level(AUDIO_PIN, 128); // silence return false; // stop timer } pwm_set_gpio_level(AUDIO_PIN, audio_data[sample_index++]); return true; // continue } void play_audio(uint gpio, const uint8_t *samples, uint32_t num_samples, uint32_t sample_rate) { sample_index = 0; // Compute interval in microseconds double interval_us = 1e6 / (double)sample_rate; // Start repeating timer add_repeating_timer_us(-interval_us, audio_callback, NULL, &audio_timer); // Wait until playback finishes while (audio_timer.alarm_id != 0 && sample_index < num_samples) { tight_loop_contents(); } } void play_tone(uint gpio, uint16_t frequency, uint32_t duration_ms) { uint32_t period_us = 1000000 / frequency; uint32_t half = period_us / 2; uint32_t cycles = (duration_ms * 1000) / period_us; for (uint32_t i = 0; i < cycles; i++) { pwm_set_gpio_level(gpio, 255); sleep_us(half); pwm_set_gpio_level(gpio, 0); sleep_us(half); } pwm_set_gpio_level(gpio, 128); } int main() { stdio_init_all(); printf("RP2040 PCM Audio Player using Timer\n"); init_pwm_audio(AUDIO_PIN); sleep_ms(1000); while (true) { printf("Playing tone...\n"); play_tone(AUDIO_PIN, 440, 300); sleep_ms(500); printf("Playing PCM audio...\n"); play_audio(AUDIO_PIN, audio_data, audio_data_len, SAMPLE_RATE); sleep_ms(1000); } return 0; }