From 7fc903760439752a058d6091de4a9f704c4c7901 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 20 Mar 2025 13:10:14 -0500 Subject: [PATCH] There's audio, but it's glitched. it only works at all with 128k or 256k non-psram builds you can hear the beep when you adjust the slider in control panel, but there's other audio overlaid on it that is kind of a weird descending tone, very regular in nature. The sample rate is set to 20k not 22.255k because of my i2s dac not liking random sample rates. Instead of using the i2s dac on the fruit jam, this uses A0 (data), A1 (lrck), A2 (bclk). It's not super convenient, and it's hard coded. --- CMakeLists.txt | 12 +++++ external/pico-extras | 2 +- external/umac | 2 +- fruitjam-build.sh | 4 +- src/main.c | 104 +++++++++++++++++++++++++++++++++++++++---- src/video_hstx.c | 8 ++-- 6 files changed, 117 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28b4723..f273c20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,9 @@ set(PSRAM_CS 47 CACHE STRING "PSRAM Chip select pin") set(PIN_USB_HOST_DP 1 CACHE STRING "USB D+ PIN") set(PIN_USB_HOST_DM 2 CACHE STRING "USB D- PIN") +set(USE_AUDIO 1 CACHE STRING "Use audio") +set(PIN_AUDIO_PWM 41 CACHE STRING "Pin for PWM audio") + # See below, -DMEMSIZE= will configure umac's memory size, # overriding defaults. @@ -136,6 +139,14 @@ else() add_compile_definitions(USE_PSRAM=0) endif() +if (USE_AUDIO) + add_subdirectory(external/pico-extras/src/rp2_common/pico_audio_i2s) + add_subdirectory(external/pico-extras/src/common/pico_audio) + add_subdirectory(external/pico-extras/src/common/pico_util_buffer) + add_compile_definitions(ENABLE_AUDIO=1 PICO_AUDIO_I2S_PIO=1 PICO_AUDIO_I2S_DMA_IRQ=0 PICO_AUDIO_I2S_DATA_PIN=40 PICO_AUDIO_I2S_CLOCK_PIN_BASE=41) + set(EXTRA_AUDIO_LIB pico_util_buffer pico_audio pico_audio_i2s) +endif() + if (TARGET tinyusb_device) add_executable(firmware src/main.c @@ -171,6 +182,7 @@ if (TARGET tinyusb_device) hardware_pio hardware_sync ${EXTRA_SD_LIB} + ${EXTRA_AUDIO_LIB} ) target_include_directories(firmware PRIVATE diff --git a/external/pico-extras b/external/pico-extras index 8606fb8..0b7be7c 160000 --- a/external/pico-extras +++ b/external/pico-extras @@ -1 +1 @@ -Subproject commit 8606fb88057873154f9b6f98a3e52e233cd988d9 +Subproject commit 0b7be7c7fcc6346f6160e96ec73f940a4d403713 diff --git a/external/umac b/external/umac index 0be2290..4dea595 160000 --- a/external/umac +++ b/external/umac @@ -1 +1 @@ -Subproject commit 0be2290d4a2176938925075eb33cfd9b1a50aab6 +Subproject commit 4dea595da2d3c616a3ac8bb7031191bbeca85b0d diff --git a/fruitjam-build.sh b/fruitjam-build.sh index e270dd1..5c27d74 100755 --- a/fruitjam-build.sh +++ b/fruitjam-build.sh @@ -39,6 +39,8 @@ while getopts "hvd:m:" o; do esac done +shift $((OPTIND-1)) + TAG=fruitjam_${DISP_WIDTH}x${DISP_HEIGHT}_${MEMSIZE}k PSRAM=$((MEMSIZE > 448 || DISP_WIDTH < 640)) if [ $PSRAM -ne 0 ] ; then @@ -71,5 +73,5 @@ cmake -S . -B build_${TAG} \ -DMEMSIZE=${MEMSIZE} \ -DUSE_HSTX=1 \ -DSD_TX=35 -DSD_RX=36 -DSD_SCK=34 -DSD_CS=39 -DUSE_SD=1 \ - ${CMAKE_ARGS} + ${CMAKE_ARGS} "$@" make -C build_${TAG} -j$(nproc) diff --git a/src/main.c b/src/main.c index 16050ce..d06b5ef 100644 --- a/src/main.c +++ b/src/main.c @@ -57,6 +57,14 @@ #include "hardware/structs/qmi.h" #include "hardware/structs/xip.h" #endif + +#if ENABLE_AUDIO +#include "pico/audio_i2s.h" +uint8_t *audio_base; +static void audio_setup(); +static bool audio_poll(); +#endif + //////////////////////////////////////////////////////////////////////////////// // Imports and data @@ -97,8 +105,8 @@ static void poll_led_etc() if (absolute_time_diff_us(last, now) > 500*1000) { last = now; - led_on ^= 1; - gpio_put(GPIO_LED_PIN, led_on); + //led_on ^= 1; + //gpio_put(GPIO_LED_PIN, led_on); } } @@ -126,11 +134,6 @@ static void copy_framebuffer() { *dest++ = *src++ ^ 0xfffffffful; } } - uint16_t *src16 = (uint16_t*)(umac_ram + umac_get_audio_offset()); - for(int i=0; i<370; i++) { - uint32_t *dest = umac_framebuffer_mirror + LONGS_PER_OUTPUT_ROW * i; - *dest = *src16++; - } #else #error Unsupported display geometry for framebuffer mirroring #endif @@ -147,7 +150,11 @@ static void poll_umac() int64_t p_1hz = absolute_time_diff_us(last_1hz, now); int64_t p_vsync = absolute_time_diff_us(last_vsync, now); - if (p_vsync >= 16667) { + bool pending_vsync = p_vsync > 16667; +#if ENABLE_AUDIO + pending_vsync |= audio_poll(); +#endif + if (pending_vsync) { #if USE_PSRAM copy_framebuffer(); #endif @@ -305,6 +312,9 @@ static void core1_main() video_init((uint32_t *)(umac_ram + umac_get_fb_offset())); #endif +#if ENABLE_AUDIO + audio_base = (uint8_t*)umac_ram + umac_get_audio_offset(); +#endif printf("Enjoyable Mac times now begin:\n\n"); while (true) { @@ -464,6 +474,10 @@ int main() stdio_init_all(); io_init(); +#if ENABLE_AUDIO + audio_setup(); +#endif + multicore_launch_core1(core1_main); printf("Starting, init usb\n"); @@ -494,3 +508,77 @@ int main() return 0; } +#if ENABLE_AUDIO +static int volscale; + + +#define SAMPLES_PER_BUFFER (370) +int16_t audio[SAMPLES_PER_BUFFER]; + +void umac_audio_trap() { +static int led_on; + led_on ^= 1; + gpio_put(GPIO_LED_PIN, 1); + int32_t offset = 128; + uint16_t *audiodata = (uint16_t*)audio_base; + int scale = volscale; + if (!scale) { + memset(audio, 0, sizeof(audio)); + return; + } + int16_t *stream = audio; + for(int i=0; i> 8; + *stream++ = a; + } +} + +struct audio_buffer_pool *producer_pool; + +static audio_format_t audio_format = { + .format = AUDIO_BUFFER_FORMAT_PCM_S16, + .sample_freq = 20000, + .channel_count = 1, +}; + +const struct audio_i2s_config config = + { + .data_pin = PICO_AUDIO_I2S_DATA_PIN, + .clock_pin_base = PICO_AUDIO_I2S_CLOCK_PIN_BASE, + .pio_sm = 0, + .dma_channel = 3 + }; + +static struct audio_buffer_format producer_format = { + .format = &audio_format, + .sample_stride = 2 +}; + +static void audio_setup() { + const struct audio_format *output_format = audio_i2s_setup(&audio_format, &config); + assert(output_format); + if (!output_format) { + panic("PicoAudio: Unable to open audio device.\n"); + } + producer_pool = audio_new_producer_pool(&producer_format, 3, SAMPLES_PER_BUFFER); + assert(producer_pool); + bool ok = audio_i2s_connect(producer_pool); + assert(ok); + audio_i2s_set_enabled(true); +} + +static bool audio_poll() { + audio_buffer_t *buffer = take_audio_buffer(producer_pool, false); + if (!buffer) return false; + gpio_put(GPIO_LED_PIN, 0); + memcpy(buffer->buffer->bytes, audio, sizeof(audio)); + buffer->sample_count = SAMPLES_PER_BUFFER; + give_audio_buffer(producer_pool, buffer); + return true; +} + +void umac_audio_cfg(int volume, int sndres) { + volscale = sndres ? 0 : 65536 * volume / 7; +} +#endif diff --git a/src/video_hstx.c b/src/video_hstx.c index 62ffe2c..fad4f40 100644 --- a/src/video_hstx.c +++ b/src/video_hstx.c @@ -300,10 +300,10 @@ void video_init(uint32_t *framebuffer) { false ); - dma_hw->ints0 = (1u << self->dma_pixel_channel); - dma_hw->inte0 = (1u << self->dma_pixel_channel); - irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler); - irq_set_enabled(DMA_IRQ_0, true); + dma_hw->ints2 = (1u << self->dma_pixel_channel); + dma_hw->inte2 = (1u << self->dma_pixel_channel); + irq_set_exclusive_handler(DMA_IRQ_2, dma_irq_handler); + irq_set_enabled(DMA_IRQ_2, true); bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS;