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.
This commit is contained in:
Jeff Epler 2025-03-20 13:10:14 -05:00
parent 42cf94e77f
commit 7fc9037604
6 changed files with 117 additions and 15 deletions

View file

@ -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=<size in KB> 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

@ -1 +1 @@
Subproject commit 8606fb88057873154f9b6f98a3e52e233cd988d9
Subproject commit 0b7be7c7fcc6346f6160e96ec73f940a4d403713

2
external/umac vendored

@ -1 +1 @@
Subproject commit 0be2290d4a2176938925075eb33cfd9b1a50aab6
Subproject commit 4dea595da2d3c616a3ac8bb7031191bbeca85b0d

View file

@ -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)

View file

@ -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<SAMPLES_PER_BUFFER; i++) {
int32_t a = (*audiodata++ & 0xff) - offset;
a = (a * scale) >> 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

View file

@ -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;