From 4cf4e3d4c2e907854ca74bf1073676c5444c6291 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 7 Mar 2025 12:26:20 -0600 Subject: [PATCH 01/55] set the stage for HSTX support --- CMakeLists.txt | 18 +++++++++++++++--- src/{video.c => video_vga.c} | 0 2 files changed, 15 insertions(+), 3 deletions(-) rename src/{video.c => video_vga.c} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 65be3ad..2fd2012 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,13 @@ set(SD_RX 4 CACHE STRING "SD SPI RX pin") set(SD_SCK 2 CACHE STRING "SD SPI SCK pin") set(SD_CS 5 CACHE STRING "SD SPI CS pin") set(SD_MHZ 5 CACHE STRING "SD SPI speed in MHz") +option(USE_HSTX "Use HSTX digital video" OFF) option(USE_VGA_RES "Video uses VGA (640x480) resolution" OFF) -set(VIDEO_PIN 18 CACHE STRING "Video GPIO base pin (followed by VS, CLK, HS)") +set(VIDEO_PIN 18 CACHE STRING "VGA Video GPIO base pin (followed by VS, CLK, HS)") +set(HSTX_CKP 12 CACHE STRING "HSTX CK+ PIN") +set(HSTX_D0P 14 CACHE STRING "HSTX D0+ PIN") +set(HSTX_D1P 16 CACHE STRING "HSTX D1+ PIN") +set(HSTX_D2P 18 CACHE STRING "HSTX D2+ PIN") # See below, -DMEMSIZE= will configure umac's memory size, # overriding defaults. @@ -94,12 +99,19 @@ else() add_compile_definitions(DISP_WIDTH=512) add_compile_definitions(DISP_HEIGHT=342) endif() -add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) + +if (USE_HSTX) + add_compile_definitions(HSTX_CKP=${HSTX_CKP} HSTX_D0P=${HSTX_D0P} HSTX_D1P=${HSTX_D1P} HSTX_D2P=${HSTX_D2P}) + set(VIDEO_SRC src/video_hstx.c) +else() + add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) + set(VIDEO_SRC src/video_vga.c) +endif() if (TARGET tinyusb_device) add_executable(firmware src/main.c - src/video.c + $(VIDEO_SRC) src/kbd.c src/hid.c ${EXTRA_SD_SRC} diff --git a/src/video.c b/src/video_vga.c similarity index 100% rename from src/video.c rename to src/video_vga.c From be0732f2f03bd5f2f5ee7899b60ddb2c67a5636b Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Mar 2025 16:14:57 -0500 Subject: [PATCH 02/55] more aspirational cmakefile changes --- CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fd2012..398c3eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ cmake_minimum_required(VERSION 3.13) # Options that should be defined when initialising the build # directory with cmake, e.g. "cmake .. -DOPTION=true": # +# Note: to build for pico2 / rp2350: cmake .. -DPICO_BOARD=pico2 option(USE_SD "Build in SD support" OFF) set(SD_TX 3 CACHE STRING "SD SPI TX pin") @@ -35,8 +36,10 @@ set(SD_RX 4 CACHE STRING "SD SPI RX pin") set(SD_SCK 2 CACHE STRING "SD SPI SCK pin") set(SD_CS 5 CACHE STRING "SD SPI CS pin") set(SD_MHZ 5 CACHE STRING "SD SPI speed in MHz") -option(USE_HSTX "Use HSTX digital video" OFF) + +option(USE_HSTX "Use HSTX digital video (only for rp2350 / pico2)" OFF) option(USE_VGA_RES "Video uses VGA (640x480) resolution" OFF) +option(USE_720P_RES "Video uses 720p (1280x720) resolution (HSTX only)" OFF) set(VIDEO_PIN 18 CACHE STRING "VGA Video GPIO base pin (followed by VS, CLK, HS)") set(HSTX_CKP 12 CACHE STRING "HSTX CK+ PIN") set(HSTX_D0P 14 CACHE STRING "HSTX D0+ PIN") @@ -111,7 +114,7 @@ endif() if (TARGET tinyusb_device) add_executable(firmware src/main.c - $(VIDEO_SRC) + ${VIDEO_SRC} src/kbd.c src/hid.c ${EXTRA_SD_SRC} From e21d01aebf772ec0417137ec69625329a36a81e8 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Mar 2025 16:15:16 -0500 Subject: [PATCH 03/55] scripts to prepare rom & floppy image --- fetch-rom-dsk.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 fetch-rom-dsk.sh diff --git a/fetch-rom-dsk.sh b/fetch-rom-dsk.sh new file mode 100644 index 0000000..75a2511 --- /dev/null +++ b/fetch-rom-dsk.sh @@ -0,0 +1,19 @@ +#!/bin/sh +mkdir -p incbin + +if ! [ -f rom.bin ]; then + if ! [ -f '4D1F8172 - MacPlus v3.ROM' ]; then + curl -L 'https://ia902205.us.archive.org/view_archive.php?archive=/18/items/mac_rom_archive_-_as_of_8-19-2011/mac_rom_archive_-_as_of_8-19-2011.zip&file=4D1F8172%20-%20MacPlus%20v3.ROM' > '4D1F8172 - MacPlus v3.ROM' + fi + ./external/umac/main -r '4D1F8172 - MacPlus v3.ROM' -W rom.bin +fi + +xxd -i < rom.bin > incbin/umac-rom.h + +if ! [ -f umac0ro.img ]; then + curl -L 'https://archive.org/download/apple-mac-os-system-3.2-finder-5.3-system-tools-1.0-512-ke-jun-1986-3.5-800k.-7z/Apple%20Mac%20OS%20%28System%203.2%20Finder%205.3%29%20%28System%20Tools%201.0%20Mac%20128%2C%20512K%29%20%28Jun%201986%29%20%283.5-400k%29.7z' > 'Apple Mac OS (System 3.2 Finder 5.3) (System Tools 1.1 Mac Plus) (Jun 1986) (3.5-800k).7z' + 7z x -so 'Apple Mac OS (System 3.2 Finder 5.3) (System Tools 1.1 Mac Plus) (Jun 1986) (3.5-800k).7z' 'Apple Mac OS (System 3.2 Finder 5.3) (System Tools 1.0 Mac 128, 512K) (Jun 1986) (3.5-400k)/System Installation.img' > umac0ro.img +fi + +xxd -i < umac0ro.img > incbin/umac-disc.h + From 0528f6a466cf5927904e07770e41d94a4f5d4944 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Mar 2025 09:12:46 -0500 Subject: [PATCH 04/55] WIP -- hstx display sort of exists but is garbled --- CMakeLists.txt | 41 ++++--- src/video_hstx.c | 292 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 317 insertions(+), 16 deletions(-) create mode 100644 src/video_hstx.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 398c3eb..a2fde67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,8 @@ cmake_minimum_required(VERSION 3.13) # directory with cmake, e.g. "cmake .. -DOPTION=true": # # Note: to build for pico2 / rp2350: cmake .. -DPICO_BOARD=pico2 +# Note: to build for fruit jam: +# cmake -DPICO_BOARD=pico2 -DUSE_HSTX=1 -S . -B build_hstx -DPICO_SDK_PATH=../pico-sdk option(USE_SD "Build in SD support" OFF) set(SD_TX 3 CACHE STRING "SD SPI TX pin") @@ -38,13 +40,16 @@ set(SD_CS 5 CACHE STRING "SD SPI CS pin") set(SD_MHZ 5 CACHE STRING "SD SPI speed in MHz") option(USE_HSTX "Use HSTX digital video (only for rp2350 / pico2)" OFF) + +# Options for HSTX output (defaults are for Adafruit FruitJam) +set(HSTX_CKP 13 CACHE STRING "HSTX CK+ PIN") +set(HSTX_D0P 15 CACHE STRING "HSTX D0+ PIN") +set(HSTX_D1P 17 CACHE STRING "HSTX D1+ PIN") +set(HSTX_D2P 19 CACHE STRING "HSTX D2+ PIN") + +# Options for analog VGA output option(USE_VGA_RES "Video uses VGA (640x480) resolution" OFF) -option(USE_720P_RES "Video uses 720p (1280x720) resolution (HSTX only)" OFF) set(VIDEO_PIN 18 CACHE STRING "VGA Video GPIO base pin (followed by VS, CLK, HS)") -set(HSTX_CKP 12 CACHE STRING "HSTX CK+ PIN") -set(HSTX_D0P 14 CACHE STRING "HSTX D0+ PIN") -set(HSTX_D1P 16 CACHE STRING "HSTX D1+ PIN") -set(HSTX_D2P 18 CACHE STRING "HSTX D2+ PIN") # See below, -DMEMSIZE= will configure umac's memory size, # overriding defaults. @@ -94,21 +99,27 @@ if (USE_SD) add_compile_definitions(SD_TX=${SD_TX} SD_RX=${SD_RX} SD_SCK=${SD_SCK} SD_CS=${SD_CS} SD_MHZ=${SD_MHZ}) endif() -if (USE_VGA_RES) +if (USE_HSTX) add_compile_definitions(USE_VGA_RES=1) add_compile_definitions(DISP_WIDTH=640) add_compile_definitions(DISP_HEIGHT=480) -else() - add_compile_definitions(DISP_WIDTH=512) - add_compile_definitions(DISP_HEIGHT=342) -endif() - -if (USE_HSTX) add_compile_definitions(HSTX_CKP=${HSTX_CKP} HSTX_D0P=${HSTX_D0P} HSTX_D1P=${HSTX_D1P} HSTX_D2P=${HSTX_D2P}) set(VIDEO_SRC src/video_hstx.c) else() - add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) - set(VIDEO_SRC src/video_vga.c) + if (USE_VGA_RES) + add_compile_definitions(USE_VGA_RES=1) + add_compile_definitions(DISP_WIDTH=640) + add_compile_definitions(DISP_HEIGHT=480) + else() + add_compile_definitions(DISP_WIDTH=512) + add_compile_definitions(DISP_HEIGHT=342) + endif() + + add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) + set(VIDEO_SRC src/video_vga.c) + + pico_generate_pio_header(firmware ${CMAKE_CURRENT_LIST_DIR}/src/pio_video.pio) + endif() if (TARGET tinyusb_device) @@ -151,8 +162,6 @@ if (TARGET tinyusb_device) incbin ) - pico_generate_pio_header(firmware ${CMAKE_CURRENT_LIST_DIR}/src/pio_video.pio) - pico_enable_stdio_uart(firmware 1) # Needed for UF2: diff --git a/src/video_hstx.c b/src/video_hstx.c new file mode 100644 index 0000000..0eb60b0 --- /dev/null +++ b/src/video_hstx.c @@ -0,0 +1,292 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "stdlib.h" + +// This is from: https://github.com/raspberrypi/pico-examples-rp2350/blob/a1/hstx/dvi_out_hstx_encoder/dvi_out_hstx_encoder.c + +#include "hardware/dma.h" +#include "hardware/gpio.h" +#include "hardware/structs/bus_ctrl.h" +#include "hardware/structs/hstx_ctrl.h" +#include "hardware/structs/hstx_fifo.h" + +// ---------------------------------------------------------------------------- +// DVI constants + +#define TMDS_CTRL_00 0x354u +#define TMDS_CTRL_01 0x0abu +#define TMDS_CTRL_10 0x154u +#define TMDS_CTRL_11 0x2abu + +#define SYNC_V0_H0 (TMDS_CTRL_00 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20)) +#define SYNC_V0_H1 (TMDS_CTRL_01 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20)) +#define SYNC_V1_H0 (TMDS_CTRL_10 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20)) +#define SYNC_V1_H1 (TMDS_CTRL_11 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20)) + +#define MODE_H_SYNC_POLARITY 0 +#define MODE_H_FRONT_PORCH 16 +#define MODE_H_SYNC_WIDTH 96 +#define MODE_H_BACK_PORCH 48 +#define MODE_H_ACTIVE_PIXELS 640 + +#define MODE_V_SYNC_POLARITY 0 +#define MODE_V_FRONT_PORCH 10 +#define MODE_V_SYNC_WIDTH 2 +#define MODE_V_BACK_PORCH 33 +#define MODE_V_ACTIVE_LINES 480 + +#define MODE_H_TOTAL_PIXELS ( \ + MODE_H_FRONT_PORCH + MODE_H_SYNC_WIDTH + \ + MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS \ + ) +#define MODE_V_TOTAL_LINES ( \ + MODE_V_FRONT_PORCH + MODE_V_SYNC_WIDTH + \ + MODE_V_BACK_PORCH + MODE_V_ACTIVE_LINES \ + ) + +#define HSTX_CMD_RAW (0x0u << 12) +#define HSTX_CMD_RAW_REPEAT (0x1u << 12) +#define HSTX_CMD_TMDS (0x2u << 12) +#define HSTX_CMD_TMDS_REPEAT (0x3u << 12) +#define HSTX_CMD_NOP (0xfu << 12) + +// ---------------------------------------------------------------------------- +// HSTX command lists + +static uint32_t vblank_line_vsync_off[] = { + HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH, + SYNC_V1_H1, + HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH, + SYNC_V1_H0, + HSTX_CMD_RAW_REPEAT | (MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS), + SYNC_V1_H1 +}; + +static uint32_t vblank_line_vsync_on[] = { + HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH, + SYNC_V0_H1, + HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH, + SYNC_V0_H0, + HSTX_CMD_RAW_REPEAT | (MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS), + SYNC_V0_H1 +}; + +static uint32_t vactive_line[] = { + HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH, + SYNC_V1_H1, + HSTX_CMD_NOP, + HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH, + SYNC_V1_H0, + HSTX_CMD_NOP, + HSTX_CMD_RAW_REPEAT | MODE_H_BACK_PORCH, + SYNC_V1_H1, + HSTX_CMD_TMDS | MODE_H_ACTIVE_PIXELS +}; + +typedef struct { + uint32_t *framebuffer; + uint32_t *dma_commands; + size_t dma_commands_len; // in words + uint8_t dma_pixel_channel; + uint8_t dma_command_channel; +} picodvi_framebuffer_obj_t; + +picodvi_framebuffer_obj_t *active_picodvi = NULL; +picodvi_framebuffer_obj_t picodvi; + +static void __not_in_flash_func(dma_irq_handler)(void) { + if (active_picodvi == NULL) { + return; + } + uint ch_num = active_picodvi->dma_pixel_channel; + dma_channel_hw_t *ch = &dma_hw->ch[ch_num]; + dma_hw->intr = 1u << ch_num; + + // Set the read_addr back to the start and trigger the first transfer (which + // will trigger the pixel channel). + ch = &dma_hw->ch[active_picodvi->dma_command_channel]; + ch->al3_read_addr_trig = (uintptr_t)active_picodvi->dma_commands; +} + +#if DISP_WIDTH != 640 || DISP_HEIGHT != 480 +#error Only VGA resolution is supported +#endif + +void video_init(uint32_t *framebuffer) { + picodvi_framebuffer_obj_t *self = &picodvi; + + // We compute all DMA transfers needed for a single frame. This ensure we don't have any super + // quick interrupts that we need to respond to. Each transfer takes two words, trans_count and + // read_addr. Active pixel lines need two transfers due to different read addresses. When pixel + // doubling, then we must also set transfer size. + size_t dma_command_size = 2; + self->dma_commands_len = (MODE_V_FRONT_PORCH + MODE_V_SYNC_WIDTH + MODE_V_BACK_PORCH + 2 * MODE_V_ACTIVE_LINES + 1) * dma_command_size; + self->dma_commands = (uint32_t *)malloc(self->dma_commands_len * sizeof(uint32_t)); + if (self->dma_commands == NULL) { + return; + } + + self->dma_pixel_channel = dma_claim_unused_channel(true); + self->dma_command_channel = dma_claim_unused_channel(true); + + size_t words_per_line; + words_per_line = DISP_WIDTH / 8 / sizeof(uint32_t); + + size_t command_word = 0; + size_t frontporch_start = MODE_V_TOTAL_LINES - MODE_V_FRONT_PORCH; + size_t frontporch_end = frontporch_start + MODE_V_FRONT_PORCH; + size_t vsync_start = 0; + size_t vsync_end = vsync_start + MODE_V_SYNC_WIDTH; + size_t backporch_start = vsync_end; + size_t backporch_end = backporch_start + MODE_V_BACK_PORCH; + size_t active_start = backporch_end; + + uint32_t dma_ctrl = (self->dma_command_channel << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB) | + (DREQ_HSTX << DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB) | + DMA_CH0_CTRL_TRIG_IRQ_QUIET_BITS | + DMA_CH0_CTRL_TRIG_INCR_READ_BITS | + DMA_CH0_CTRL_TRIG_EN_BITS; + uint32_t dma_pixel_ctrl = dma_ctrl | (DMA_SIZE_32 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB); + dma_ctrl |= (DMA_SIZE_32 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB); + + uint32_t dma_write_addr = (uint32_t)&hstx_fifo_hw->fifo; + // Write ctrl and write_addr once when not pixel doubling because they don't + // change. (write_addr doesn't change when pixel doubling either but we need + // to rewrite it because it is after the ctrl register.) + dma_channel_hw_addr(self->dma_pixel_channel)->al1_ctrl = dma_ctrl; + dma_channel_hw_addr(self->dma_pixel_channel)->al1_write_addr = dma_write_addr; + + for (size_t v_scanline = 0; v_scanline < MODE_V_TOTAL_LINES; v_scanline++) { + if (vsync_start <= v_scanline && v_scanline < vsync_end) { + self->dma_commands[command_word++] = count_of(vblank_line_vsync_on); + self->dma_commands[command_word++] = (uintptr_t)vblank_line_vsync_on; + } else if (backporch_start <= v_scanline && v_scanline < backporch_end) { + self->dma_commands[command_word++] = count_of(vblank_line_vsync_off); + self->dma_commands[command_word++] = (uintptr_t)vblank_line_vsync_off; + } else if (frontporch_start <= v_scanline && v_scanline < frontporch_end) { + self->dma_commands[command_word++] = count_of(vblank_line_vsync_off); + self->dma_commands[command_word++] = (uintptr_t)vblank_line_vsync_off; + } else { + self->dma_commands[command_word++] = count_of(vactive_line); + self->dma_commands[command_word++] = (uintptr_t)vactive_line; + size_t row = v_scanline - active_start; + size_t transfer_count = words_per_line; + self->dma_commands[command_word++] = transfer_count; + uint32_t *row_start = &framebuffer[row * words_per_line]; + self->dma_commands[command_word++] = (uintptr_t)row_start; + } + } + // Last command is NULL which will trigger an IRQ. + self->dma_commands[command_word++] = 0; + self->dma_commands[command_word++] = 0; + + // B&W + uint8_t rot = 25; // ??? really ??? + hstx_ctrl_hw->expand_tmds = + rot << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB | + rot << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB | + rot << HSTX_CTRL_EXPAND_TMDS_L0_ROT_LSB; + size_t shifts_before_empty = 32; + size_t color_depth = 1; + + // Pixels come in 32 bits at a time. color_depth dictates the number + // of pixels per word. Control symbols (RAW) are an entire 32-bit word. + hstx_ctrl_hw->expand_shift = + shifts_before_empty << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB | + color_depth << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB | + 1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB | + 0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB; + + // Serial output config: clock period of 5 cycles, pop from command + // expander every 5 cycles, shift the output shiftreg by 2 every cycle. + hstx_ctrl_hw->csr = 0; + hstx_ctrl_hw->csr = + HSTX_CTRL_CSR_EXPAND_EN_BITS | + 5u << HSTX_CTRL_CSR_CLKDIV_LSB | + 5u << HSTX_CTRL_CSR_N_SHIFTS_LSB | + 2u << HSTX_CTRL_CSR_SHIFT_LSB | + HSTX_CTRL_CSR_EN_BITS; + + // XXX this may be wrong, because pico-mac is using an overclock (but is it OC'ing HSTX? not sure) + + // Note we are leaving the HSTX clock at the SDK default of 125 MHz; since + // we shift out two bits per HSTX clock cycle, this gives us an output of + // 250 Mbps, which is very close to the bit clock for 480p 60Hz (252 MHz). + // If we want the exact rate then we'll have to reconfigure PLLs. + +#define HSTX_FIRST_PIN 12 + + // Setup the data to pin mapping. + hstx_ctrl_hw->bit[(HSTX_CKP ) - HSTX_FIRST_PIN] = HSTX_CTRL_BIT0_CLK_BITS; + hstx_ctrl_hw->bit[(HSTX_CKP ^ 1) - HSTX_FIRST_PIN] = HSTX_CTRL_BIT0_CLK_BITS | HSTX_CTRL_BIT0_INV_BITS; + + const int pinout[] = { HSTX_D0P, HSTX_D1P, HSTX_D2P }; + + for(uint lane = 0; lane < 3; lane++ ) { + int bit = pinout[lane]; + + uint32_t lane_data_sel_bits = + (lane * 10 ) << HSTX_CTRL_BIT0_SEL_P_LSB | + (lane * 10 + 1) << HSTX_CTRL_BIT0_SEL_N_LSB; + // The two halves of each pair get identical data, but one pin is inverted. + hstx_ctrl_hw->bit[(bit ) - HSTX_FIRST_PIN] = lane_data_sel_bits; + hstx_ctrl_hw->bit[(bit ^ 1) - HSTX_FIRST_PIN] = lane_data_sel_bits | HSTX_CTRL_BIT0_INV_BITS; + } + + for (int i = 12; i <= 19; ++i) { + gpio_set_function(i, 0); // HSTX + } + + dma_channel_config c; + c = dma_channel_get_default_config(self->dma_command_channel); + channel_config_set_transfer_data_size(&c, DMA_SIZE_32); + channel_config_set_read_increment(&c, true); + channel_config_set_write_increment(&c, true); + // This wraps the transfer back to the start of the write address. + size_t wrap = 3; // 8 bytes because we write two DMA registers. + volatile uint32_t *write_addr = &dma_hw->ch[self->dma_pixel_channel].al3_transfer_count; + channel_config_set_ring(&c, true, wrap); + // No chain because we use an interrupt to reload this channel instead of a + // third channel. + dma_channel_configure( + self->dma_command_channel, + &c, + write_addr, + self->dma_commands, + (1 << wrap) / sizeof(uint32_t), + false + ); + + dma_hw->ints1 = (1u << self->dma_pixel_channel); + dma_hw->inte1 = (1u << self->dma_pixel_channel); + irq_set_exclusive_handler(DMA_IRQ_1, dma_irq_handler); + irq_set_enabled(DMA_IRQ_1, true); + + bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS; + + active_picodvi = self; + + dma_irq_handler(); +} From e60a4d174ba0a39d57fb2787f715f9e79068e3c1 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Mar 2025 09:36:19 -0500 Subject: [PATCH 05/55] still WIP --- CMakeLists.txt | 2 +- src/video_hstx.c | 32 ++++++++++++++++++-------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a2fde67..8878289 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,7 +88,7 @@ set(UMAC_SOURCES ) set(MEMSIZE 128 CACHE STRING "Memory size, in KB") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -DPICO -DMUSASHI_CNF=\\\"../include/m68kconf.h\\\" -DUMAC_MEMSIZE=${MEMSIZE}") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -g3 -O3 -DPICO -DMUSASHI_CNF=\\\"../include/m68kconf.h\\\" -DUMAC_MEMSIZE=${MEMSIZE}") if (USE_SD) add_compile_definitions(USE_SD=1) diff --git a/src/video_hstx.c b/src/video_hstx.c index 0eb60b0..5f2574e 100644 --- a/src/video_hstx.c +++ b/src/video_hstx.c @@ -106,7 +106,6 @@ static uint32_t vactive_line[] = { }; typedef struct { - uint32_t *framebuffer; uint32_t *dma_commands; size_t dma_commands_len; // in words uint8_t dma_pixel_channel; @@ -151,8 +150,7 @@ void video_init(uint32_t *framebuffer) { self->dma_pixel_channel = dma_claim_unused_channel(true); self->dma_command_channel = dma_claim_unused_channel(true); - size_t words_per_line; - words_per_line = DISP_WIDTH / 8 / sizeof(uint32_t); + size_t words_per_line = DISP_WIDTH / (8 * sizeof(uint32_t)); size_t command_word = 0; size_t frontporch_start = MODE_V_TOTAL_LINES - MODE_V_FRONT_PORCH; @@ -169,6 +167,7 @@ void video_init(uint32_t *framebuffer) { DMA_CH0_CTRL_TRIG_INCR_READ_BITS | DMA_CH0_CTRL_TRIG_EN_BITS; uint32_t dma_pixel_ctrl = dma_ctrl | (DMA_SIZE_32 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB); + // dma_pixel_ctrl |= DMA_CH0_CTRL_TRIG_BSWAP_BITS; dma_ctrl |= (DMA_SIZE_32 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB); uint32_t dma_write_addr = (uint32_t)&hstx_fifo_hw->fifo; @@ -203,19 +202,24 @@ void video_init(uint32_t *framebuffer) { self->dma_commands[command_word++] = 0; // B&W - uint8_t rot = 25; // ??? really ??? - hstx_ctrl_hw->expand_tmds = - rot << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB | - rot << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB | - rot << HSTX_CTRL_EXPAND_TMDS_L0_ROT_LSB; - size_t shifts_before_empty = 32; size_t color_depth = 1; + uint8_t rot = 1; // 24 + color_depth; + hstx_ctrl_hw->expand_tmds = + (color_depth - 1) << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB | + rot << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB | + (color_depth - 1) << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB | + rot << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB | + (color_depth - 1) << HSTX_CTRL_EXPAND_TMDS_L0_NBITS_LSB | + rot << HSTX_CTRL_EXPAND_TMDS_L0_ROT_LSB; + size_t pixels_per_word = 32; + size_t shifts_before_empty = (pixels_per_word % 32); + size_t shift_amount = color_depth % 32; // Pixels come in 32 bits at a time. color_depth dictates the number // of pixels per word. Control symbols (RAW) are an entire 32-bit word. hstx_ctrl_hw->expand_shift = - shifts_before_empty << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB | - color_depth << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB | + (shifts_before_empty << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB) | + (shift_amount << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB) | 1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB | 0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB; @@ -224,9 +228,9 @@ void video_init(uint32_t *framebuffer) { hstx_ctrl_hw->csr = 0; hstx_ctrl_hw->csr = HSTX_CTRL_CSR_EXPAND_EN_BITS | - 5u << HSTX_CTRL_CSR_CLKDIV_LSB | - 5u << HSTX_CTRL_CSR_N_SHIFTS_LSB | - 2u << HSTX_CTRL_CSR_SHIFT_LSB | + (5u << HSTX_CTRL_CSR_CLKDIV_LSB) | + (5u << HSTX_CTRL_CSR_N_SHIFTS_LSB) | + (2u << HSTX_CTRL_CSR_SHIFT_LSB) | HSTX_CTRL_CSR_EN_BITS; // XXX this may be wrong, because pico-mac is using an overclock (but is it OC'ing HSTX? not sure) From a939ea65a15ae7dc76dab6b1bc35d57d89cfc3d9 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Mar 2025 10:11:30 -0500 Subject: [PATCH 06/55] WIP fix pixel ctrl value & how row start is calculated --- src/video_hstx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video_hstx.c b/src/video_hstx.c index 5f2574e..5541cd0 100644 --- a/src/video_hstx.c +++ b/src/video_hstx.c @@ -174,7 +174,7 @@ void video_init(uint32_t *framebuffer) { // Write ctrl and write_addr once when not pixel doubling because they don't // change. (write_addr doesn't change when pixel doubling either but we need // to rewrite it because it is after the ctrl register.) - dma_channel_hw_addr(self->dma_pixel_channel)->al1_ctrl = dma_ctrl; + dma_channel_hw_addr(self->dma_pixel_channel)->al1_ctrl = dma_pixel_ctrl; dma_channel_hw_addr(self->dma_pixel_channel)->al1_write_addr = dma_write_addr; for (size_t v_scanline = 0; v_scanline < MODE_V_TOTAL_LINES; v_scanline++) { @@ -193,8 +193,8 @@ void video_init(uint32_t *framebuffer) { size_t row = v_scanline - active_start; size_t transfer_count = words_per_line; self->dma_commands[command_word++] = transfer_count; - uint32_t *row_start = &framebuffer[row * words_per_line]; - self->dma_commands[command_word++] = (uintptr_t)row_start; + uintptr_t row_start = row * (DISP_WIDTH / 8) + (uintptr_t)framebuffer; + self->dma_commands[command_word++] = row_start; } } // Last command is NULL which will trigger an IRQ. From 002236b93a2415fe2ce78cd03688f85f01e7e9dc Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Mar 2025 10:19:19 -0500 Subject: [PATCH 07/55] WIP don't optimize the setup function at all --- src/video_hstx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video_hstx.c b/src/video_hstx.c index 5541cd0..76ab416 100644 --- a/src/video_hstx.c +++ b/src/video_hstx.c @@ -133,6 +133,7 @@ static void __not_in_flash_func(dma_irq_handler)(void) { #error Only VGA resolution is supported #endif +__attribute__((optimize("-O0"))) void video_init(uint32_t *framebuffer) { picodvi_framebuffer_obj_t *self = &picodvi; From cd730374ebfe694d6e566c8c04ba5662fcadba79 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Mar 2025 11:22:39 -0500 Subject: [PATCH 08/55] bits are emerging in the right order --- src/video_hstx.c | 70 +++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/src/video_hstx.c b/src/video_hstx.c index 76ab416..0b96fdd 100644 --- a/src/video_hstx.c +++ b/src/video_hstx.c @@ -72,37 +72,49 @@ #define HSTX_CMD_TMDS_REPEAT (0x3u << 12) #define HSTX_CMD_NOP (0xfu << 12) +#define DO_BSWAP (1) +#if DO_BSWAP +#define BSWAP_MAYBE(x) (\ + ((x) & 0xff) << 24 \ +| (((x) >> 8) & 0xff) << 16 \ +| (((x) >> 16) & 0xff) << 8 \ +| (((x) >> 24) & 0xff) \ +) +#else +#define BSWAP_MAYBE(x) (x) +#endif + // ---------------------------------------------------------------------------- // HSTX command lists static uint32_t vblank_line_vsync_off[] = { - HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH, - SYNC_V1_H1, - HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH, - SYNC_V1_H0, - HSTX_CMD_RAW_REPEAT | (MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS), - SYNC_V1_H1 + BSWAP_MAYBE(HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH), + BSWAP_MAYBE(SYNC_V1_H1), + BSWAP_MAYBE(HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH), + BSWAP_MAYBE(SYNC_V1_H0), + BSWAP_MAYBE(HSTX_CMD_RAW_REPEAT | (MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS)), + BSWAP_MAYBE(SYNC_V1_H1), }; static uint32_t vblank_line_vsync_on[] = { - HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH, - SYNC_V0_H1, - HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH, - SYNC_V0_H0, - HSTX_CMD_RAW_REPEAT | (MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS), - SYNC_V0_H1 + BSWAP_MAYBE(HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH), + BSWAP_MAYBE(SYNC_V0_H1), + BSWAP_MAYBE(HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH), + BSWAP_MAYBE(SYNC_V0_H0), + BSWAP_MAYBE(HSTX_CMD_RAW_REPEAT | (MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS)), + BSWAP_MAYBE(SYNC_V0_H1), }; static uint32_t vactive_line[] = { - HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH, - SYNC_V1_H1, - HSTX_CMD_NOP, - HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH, - SYNC_V1_H0, - HSTX_CMD_NOP, - HSTX_CMD_RAW_REPEAT | MODE_H_BACK_PORCH, - SYNC_V1_H1, - HSTX_CMD_TMDS | MODE_H_ACTIVE_PIXELS + BSWAP_MAYBE(HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH), + BSWAP_MAYBE(SYNC_V1_H1), + BSWAP_MAYBE(HSTX_CMD_NOP), + BSWAP_MAYBE(HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH), + BSWAP_MAYBE(SYNC_V1_H0), + BSWAP_MAYBE(HSTX_CMD_NOP), + BSWAP_MAYBE(HSTX_CMD_RAW_REPEAT | MODE_H_BACK_PORCH), + BSWAP_MAYBE(SYNC_V1_H1), + BSWAP_MAYBE(HSTX_CMD_TMDS | MODE_H_ACTIVE_PIXELS), }; typedef struct { @@ -133,7 +145,7 @@ static void __not_in_flash_func(dma_irq_handler)(void) { #error Only VGA resolution is supported #endif -__attribute__((optimize("-O0"))) + void video_init(uint32_t *framebuffer) { picodvi_framebuffer_obj_t *self = &picodvi; @@ -151,7 +163,10 @@ void video_init(uint32_t *framebuffer) { self->dma_pixel_channel = dma_claim_unused_channel(true); self->dma_command_channel = dma_claim_unused_channel(true); - size_t words_per_line = DISP_WIDTH / (8 * sizeof(uint32_t)); + size_t pixels_per_word = 32; + size_t words_per_line = DISP_WIDTH / pixels_per_word; + uint8_t rot = 25; // 24 + color_depth; + size_t shift_amount = 31; // color_depth % 32; size_t command_word = 0; size_t frontporch_start = MODE_V_TOTAL_LINES - MODE_V_FRONT_PORCH; @@ -167,8 +182,10 @@ void video_init(uint32_t *framebuffer) { DMA_CH0_CTRL_TRIG_IRQ_QUIET_BITS | DMA_CH0_CTRL_TRIG_INCR_READ_BITS | DMA_CH0_CTRL_TRIG_EN_BITS; - uint32_t dma_pixel_ctrl = dma_ctrl | (DMA_SIZE_32 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB); - // dma_pixel_ctrl |= DMA_CH0_CTRL_TRIG_BSWAP_BITS; + uint32_t dma_pixel_ctrl = dma_ctrl | ((pixels_per_word == 32 ? DMA_SIZE_32 : DMA_SIZE_16) << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB); +#if DO_BSWAP + dma_pixel_ctrl |= DMA_CH0_CTRL_TRIG_BSWAP_BITS; +#endif dma_ctrl |= (DMA_SIZE_32 << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB); uint32_t dma_write_addr = (uint32_t)&hstx_fifo_hw->fifo; @@ -204,7 +221,6 @@ void video_init(uint32_t *framebuffer) { // B&W size_t color_depth = 1; - uint8_t rot = 1; // 24 + color_depth; hstx_ctrl_hw->expand_tmds = (color_depth - 1) << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB | rot << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB | @@ -212,9 +228,7 @@ void video_init(uint32_t *framebuffer) { rot << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB | (color_depth - 1) << HSTX_CTRL_EXPAND_TMDS_L0_NBITS_LSB | rot << HSTX_CTRL_EXPAND_TMDS_L0_ROT_LSB; - size_t pixels_per_word = 32; size_t shifts_before_empty = (pixels_per_word % 32); - size_t shift_amount = color_depth % 32; // Pixels come in 32 bits at a time. color_depth dictates the number // of pixels per word. Control symbols (RAW) are an entire 32-bit word. From 6805b1191bf49147e425c44e0708a5d3f1600d8a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Mar 2025 14:00:50 -0500 Subject: [PATCH 09/55] last tweaks? --- src/main.c | 2 +- src/video_hstx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index 53c2c62..e347cc3 100644 --- a/src/main.c +++ b/src/main.c @@ -265,7 +265,7 @@ static void core1_main() int main() { - set_sys_clock_khz(250*1000, true); + // set_sys_clock_khz(250*1000, true); stdio_init_all(); io_init(); diff --git a/src/video_hstx.c b/src/video_hstx.c index 0b96fdd..f1816b6 100644 --- a/src/video_hstx.c +++ b/src/video_hstx.c @@ -165,7 +165,7 @@ void video_init(uint32_t *framebuffer) { size_t pixels_per_word = 32; size_t words_per_line = DISP_WIDTH / pixels_per_word; - uint8_t rot = 25; // 24 + color_depth; + uint8_t rot = 24; // 24 + color_depth; size_t shift_amount = 31; // color_depth % 32; size_t command_word = 0; From d0a29092b6f273e8f70eaddf1120718994c845ef Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Mar 2025 14:19:15 -0500 Subject: [PATCH 10/55] WIP switching to pico-pio-usb --- CMakeLists.txt | 7 +++++++ include/tusb_config.h | 2 ++ src/main.c | 9 ++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8878289..6a2c61e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,10 @@ set(HSTX_D2P 19 CACHE STRING "HSTX D2+ PIN") option(USE_VGA_RES "Video uses VGA (640x480) resolution" OFF) set(VIDEO_PIN 18 CACHE STRING "VGA Video GPIO base pin (followed by VS, CLK, HS)") +# Pins for PIO-based USB host +set(PIN_USB_HOST_DP CACHE STRING "1") +set(PIN_USB_HOST_DM CACHE STRING "2") + # See below, -DMEMSIZE= will configure umac's memory size, # overriding defaults. @@ -122,6 +126,9 @@ else() endif() +add_compile_definitions(PIN_USB_HOST_DP=${PIN_USB_HOST_DP}) +add_compile_definitions(PIN_USB_HOST_DM=${PIN_USB_HOST_DM}) + if (TARGET tinyusb_device) add_executable(firmware src/main.c diff --git a/include/tusb_config.h b/include/tusb_config.h index ba1b92f..cbe8523 100644 --- a/include/tusb_config.h +++ b/include/tusb_config.h @@ -83,6 +83,8 @@ // max device support (excluding hub device) #define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports +#define CFG_TUH_RPI_PIO_USB 1 + //------------- HID -------------// #define CFG_TUH_HID_EPIN_BUFSIZE 64 #define CFG_TUH_HID_EPOUT_BUFSIZE 64 diff --git a/src/main.c b/src/main.c index e347cc3..42c18f6 100644 --- a/src/main.c +++ b/src/main.c @@ -273,7 +273,14 @@ int main() multicore_launch_core1(core1_main); printf("Starting, init usb\n"); - tusb_init(); + + pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + _Static_assert(PIN_USB_HOST_DP + 1 == PIN_USB_HOST_DM || PIN_USB_HOST_DP - 1 == PIN_USB_HOST_DM, "Permitted USB D+/D- configuration"); + pio_cfg.pinout = PIN_USB_HOST_DP + 1 == PIN_USB_HOST_DM ? PIO_USB_PINOUT_DPDM : PIO_USB_PINOUT_DMDP; + pio_cfg.pin_dp = PIN_USB_HOST_DP; + tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg); + + tuh_init(BOARD_TUH_RHPORT); /* This happens on core 0: */ while (true) { From 6c18cee5ec670ce4e75fbeaff3147e061cd05012 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Mar 2025 15:05:19 -0500 Subject: [PATCH 11/55] USB mouse works! --- .gitmodules | 6 ++++++ CMakeLists.txt | 18 ++++++++++++++---- include/tusb_config.h | 4 ++++ lib/Pico-PIO-USB | 1 + lib/tinyusb | 1 + src/hid.c | 2 +- src/main.c | 15 +++++++++++++-- 7 files changed, 40 insertions(+), 7 deletions(-) create mode 160000 lib/Pico-PIO-USB create mode 160000 lib/tinyusb diff --git a/.gitmodules b/.gitmodules index 0e239de..2cfb244 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,9 @@ [submodule "external/no-OS-FatFS-SD-SPI-RPi-Pico"] path = external/no-OS-FatFS-SD-SPI-RPi-Pico url = https://github.com/evansm7/no-OS-FatFS-SD-SPI-RPi-Pico.git +[submodule "lib/tinyusb"] + path = lib/tinyusb + url = https://github.com/hathach/tinyusb +[submodule "lib/Pico-PIO-USB"] + path = lib/Pico-PIO-USB + url = https://github.com/tannewt/Pico-PIO-USB diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a2c61e..8b019ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,9 @@ cmake_minimum_required(VERSION 3.13) # Note: to build for fruit jam: # cmake -DPICO_BOARD=pico2 -DUSE_HSTX=1 -S . -B build_hstx -DPICO_SDK_PATH=../pico-sdk +set(PICO_TINYUSB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib/tinyusb) +set(PIOUSB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib/Pico-PIO-USB) + option(USE_SD "Build in SD support" OFF) set(SD_TX 3 CACHE STRING "SD SPI TX pin") set(SD_RX 4 CACHE STRING "SD SPI RX pin") @@ -71,8 +74,6 @@ pico_sdk_init() set(FAMILY rp2040) set(BOARD raspberry_pi_pico) -set(TINYUSB_PATH ${PICO_SDK_PATH}/lib/tinyusb) - # umac subproject (and Musashi sub-subproject) set(UMAC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external/umac) set(UMAC_MUSASHI_PATH ${UMAC_PATH}/external/Musashi) @@ -128,6 +129,8 @@ endif() add_compile_definitions(PIN_USB_HOST_DP=${PIN_USB_HOST_DP}) add_compile_definitions(PIN_USB_HOST_DM=${PIN_USB_HOST_DM}) +add_compile_definitions(PICO_DEFAULT_PIO_USB_DP_PIN=${PIN_USB_HOST_DP}) +add_compile_definitions(PICO_DEFAULT_PIO_USB_DM_PIN=${PIN_USB_HOST_DM}) if (TARGET tinyusb_device) add_executable(firmware @@ -137,6 +140,11 @@ if (TARGET tinyusb_device) src/hid.c ${EXTRA_SD_SRC} + ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c + ${PIOUSB_PATH}/src/pio_usb.c + ${PIOUSB_PATH}/src/pio_usb_host.c + ${PIOUSB_PATH}/src/usb_crc.c + ${UMAC_SOURCES} ) @@ -163,10 +171,12 @@ if (TARGET tinyusb_device) target_include_directories(firmware PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include - ${TINYUSB_PATH}/hw - ${TINYUSB_PATH}/src + ${PICO_TINYUSB_PATH}/hw + ${PICO_TINYUSB_PATH}/src ${UMAC_INCLUDE_PATHS} + ${PIOUSB_PATH}/src incbin + ${CMAKE_CURRENT_LIST_DIR} ) pico_enable_stdio_uart(firmware 1) diff --git a/include/tusb_config.h b/include/tusb_config.h index cbe8523..88be64d 100644 --- a/include/tusb_config.h +++ b/include/tusb_config.h @@ -89,6 +89,10 @@ #define CFG_TUH_HID_EPIN_BUFSIZE 64 #define CFG_TUH_HID_EPOUT_BUFSIZE 64 +#ifndef BOARD_TUH_RHPORT +#define BOARD_TUH_RHPORT 1 +#endif + #ifdef __cplusplus } #endif diff --git a/lib/Pico-PIO-USB b/lib/Pico-PIO-USB new file mode 160000 index 0000000..1862cc0 --- /dev/null +++ b/lib/Pico-PIO-USB @@ -0,0 +1 @@ +Subproject commit 1862cc008e026cbd07b97b28e29eafb5f38b35fb diff --git a/lib/tinyusb b/lib/tinyusb new file mode 160000 index 0000000..5333d04 --- /dev/null +++ b/lib/tinyusb @@ -0,0 +1 @@ +Subproject commit 5333d042f9384ec1cc0663a2708c0ca7cb5cdc32 diff --git a/src/hid.c b/src/hid.c index caae549..6f74eeb 100644 --- a/src/hid.c +++ b/src/hid.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "bsp/rp2040/board.h" +#include "bsp/rp2040/boards/adafruit_fruit_jam/board.h" #include "tusb.h" #include "kbd.h" diff --git a/src/main.c b/src/main.c index 42c18f6..3418a03 100644 --- a/src/main.c +++ b/src/main.c @@ -40,7 +40,8 @@ #include "video.h" #include "kbd.h" -#include "bsp/rp2040/board.h" +#include "pio_usb_configuration.h" +#include "bsp/rp2040/boards/adafruit_fruit_jam/board.h" #include "tusb.h" #include "umac.h" @@ -275,9 +276,19 @@ int main() printf("Starting, init usb\n"); pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + pio_cfg.tx_ch = 2; + pio_cfg.pin_dp = PICO_DEFAULT_PIO_USB_DP_PIN; + +//#ifdef PICO_DEFAULT_PIO_USB_VBUSEN_PIN + gpio_init(PICO_DEFAULT_PIO_USB_VBUSEN_PIN); + gpio_set_dir(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, GPIO_OUT); + gpio_put(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, PICO_DEFAULT_PIO_USB_VBUSEN_STATE); +//#endif + +#if 0 _Static_assert(PIN_USB_HOST_DP + 1 == PIN_USB_HOST_DM || PIN_USB_HOST_DP - 1 == PIN_USB_HOST_DM, "Permitted USB D+/D- configuration"); pio_cfg.pinout = PIN_USB_HOST_DP + 1 == PIN_USB_HOST_DM ? PIO_USB_PINOUT_DPDM : PIO_USB_PINOUT_DMDP; - pio_cfg.pin_dp = PIN_USB_HOST_DP; +#endif tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg); tuh_init(BOARD_TUH_RHPORT); From 171199e73bb204f117d5096e77867a864d068e62 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 12:23:51 -0500 Subject: [PATCH 12/55] pico_generate_pio_header must be moved later --- CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b019ef..b2c5972 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,7 +123,6 @@ else() add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) set(VIDEO_SRC src/video_vga.c) - pico_generate_pio_header(firmware ${CMAKE_CURRENT_LIST_DIR}/src/pio_video.pio) endif() @@ -179,6 +178,10 @@ if (TARGET tinyusb_device) ${CMAKE_CURRENT_LIST_DIR} ) + if (NOT USE_HSTX) + pico_generate_pio_header(firmware ${CMAKE_CURRENT_LIST_DIR}/src/pio_video.pio) + endif() + pico_enable_stdio_uart(firmware 1) # Needed for UF2: From be8b5971971ca6c0826276cd138265894c7c7a9c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 13:14:22 -0500 Subject: [PATCH 13/55] Fix cmake default usb pins (they're fruit jammin') --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2c5972..2101969 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,8 +55,8 @@ option(USE_VGA_RES "Video uses VGA (640x480) resolution" OFF) set(VIDEO_PIN 18 CACHE STRING "VGA Video GPIO base pin (followed by VS, CLK, HS)") # Pins for PIO-based USB host -set(PIN_USB_HOST_DP CACHE STRING "1") -set(PIN_USB_HOST_DM CACHE STRING "2") +set(PIN_USB_HOST_DP 1 CACHE STRING "USB D+ PIN") +set(PIN_USB_HOST_DM 2 CACHE STRING "USB D- PIN") # See below, -DMEMSIZE= will configure umac's memory size, # overriding defaults. From bea9eeb99cbc3ed249915da0f225d2ea48802704 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 13:14:28 -0500 Subject: [PATCH 14/55] suggest SD pins --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2101969..9997970 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ cmake_minimum_required(VERSION 3.13) # # Note: to build for pico2 / rp2350: cmake .. -DPICO_BOARD=pico2 # Note: to build for fruit jam: -# cmake -DPICO_BOARD=pico2 -DUSE_HSTX=1 -S . -B build_hstx -DPICO_SDK_PATH=../pico-sdk +# cmake -DBOARD=adafruit_fruit_jam -DPICO_BOARD=pico2 -DUSE_HSTX=1 -S . -B build_hstx -DPICO_SDK_PATH=../pico-sdk -DSD_TX=35 -DSD_RX=36 -DSD_SCK=34 -DSD_CS=39 set(PICO_TINYUSB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib/tinyusb) set(PIOUSB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib/Pico-PIO-USB) @@ -45,6 +45,7 @@ set(SD_MHZ 5 CACHE STRING "SD SPI speed in MHz") option(USE_HSTX "Use HSTX digital video (only for rp2350 / pico2)" OFF) # Options for HSTX output (defaults are for Adafruit FruitJam) +# HSTX always uses 640x480 for now set(HSTX_CKP 13 CACHE STRING "HSTX CK+ PIN") set(HSTX_D0P 15 CACHE STRING "HSTX D0+ PIN") set(HSTX_D1P 17 CACHE STRING "HSTX D1+ PIN") From 81b92747f114939e7aeb8eff026356b6803e4c62 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 13:52:09 -0500 Subject: [PATCH 15/55] Swap HSTX pins this is a _workaround_ for the fact that the mac framebuffer is inverted. we'll probably ditch it again once we copy the (512x342) framebuffer from PSRAM to SRAM.... --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9997970..5671c05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,10 +46,10 @@ option(USE_HSTX "Use HSTX digital video (only for rp2350 / pico2)" OFF) # Options for HSTX output (defaults are for Adafruit FruitJam) # HSTX always uses 640x480 for now -set(HSTX_CKP 13 CACHE STRING "HSTX CK+ PIN") -set(HSTX_D0P 15 CACHE STRING "HSTX D0+ PIN") -set(HSTX_D1P 17 CACHE STRING "HSTX D1+ PIN") -set(HSTX_D2P 19 CACHE STRING "HSTX D2+ PIN") +set(HSTX_CKP 12 CACHE STRING "HSTX CK+ PIN") +set(HSTX_D0P 14 CACHE STRING "HSTX D0+ PIN") +set(HSTX_D1P 16 CACHE STRING "HSTX D1+ PIN") +set(HSTX_D2P 18 CACHE STRING "HSTX D2+ PIN") # Options for analog VGA output option(USE_VGA_RES "Video uses VGA (640x480) resolution" OFF) From 691046fe6aa5a6c9f3bd6dccaf2b364a7d30e03f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 13:52:22 -0500 Subject: [PATCH 16/55] Make SPI instance selectable (not needed, as it turns out) --- src/sd_hw_config.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sd_hw_config.c b/src/sd_hw_config.c index db270a2..446ff7d 100755 --- a/src/sd_hw_config.c +++ b/src/sd_hw_config.c @@ -38,9 +38,13 @@ socket, which SPI it is driven by, and how it is wired. // Hardware Configuration of SPI "objects" // Note: multiple SD cards can be driven by one SPI if they use different slave // selects. +#ifndef SD_SPI_INST +#define SD_SPI_INST (spi0) +#endif + static spi_t spis[] = { // One for each SPI. { - .hw_inst = spi0, // SPI component + .hw_inst = SD_SPI_INST, // SPI component .miso_gpio = SD_RX, // GPIO number (not pin number) .mosi_gpio = SD_TX, .sck_gpio = SD_SCK, From bcb13e295a4d8bd678a2a7f14f53923ff719e452 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 13:52:30 -0500 Subject: [PATCH 17/55] hstx: Use DMA_IRQ_0 to avoid conflict with SD card reading --- src/video_hstx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/video_hstx.c b/src/video_hstx.c index f1816b6..347bafd 100644 --- a/src/video_hstx.c +++ b/src/video_hstx.c @@ -298,10 +298,10 @@ void video_init(uint32_t *framebuffer) { false ); - dma_hw->ints1 = (1u << self->dma_pixel_channel); - dma_hw->inte1 = (1u << self->dma_pixel_channel); - irq_set_exclusive_handler(DMA_IRQ_1, dma_irq_handler); - irq_set_enabled(DMA_IRQ_1, true); + 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); bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS; From 9fb0ec8f60976fc8845a2e2854badfbb3db2ec4f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 20:14:56 -0500 Subject: [PATCH 18/55] Add psram support it seems to be a tad slower but what do you want....! --- CMakeLists.txt | 31 +++++--- src/main.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 208 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5671c05..fa79eb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,9 @@ set(HSTX_D2P 18 CACHE STRING "HSTX D2+ PIN") option(USE_VGA_RES "Video uses VGA (640x480) resolution" OFF) set(VIDEO_PIN 18 CACHE STRING "VGA Video GPIO base pin (followed by VS, CLK, HS)") +option(USE_PSRAM "Locate main Mac ram in PSRAM (only for rp2350 / pico 2)" OFF) +set(PSRAM_CS 47 CACHE STRING "PSRAM Chip select pin") + # Pins for PIO-based USB host set(PIN_USB_HOST_DP 1 CACHE STRING "USB D+ PIN") set(PIN_USB_HOST_DM 2 CACHE STRING "USB D- PIN") @@ -112,19 +115,17 @@ if (USE_HSTX) add_compile_definitions(HSTX_CKP=${HSTX_CKP} HSTX_D0P=${HSTX_D0P} HSTX_D1P=${HSTX_D1P} HSTX_D2P=${HSTX_D2P}) set(VIDEO_SRC src/video_hstx.c) else() - if (USE_VGA_RES) - add_compile_definitions(USE_VGA_RES=1) - add_compile_definitions(DISP_WIDTH=640) - add_compile_definitions(DISP_HEIGHT=480) - else() - add_compile_definitions(DISP_WIDTH=512) - add_compile_definitions(DISP_HEIGHT=342) - endif() - - add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) - set(VIDEO_SRC src/video_vga.c) - + if (USE_VGA_RES) + add_compile_definitions(USE_VGA_RES=1) + add_compile_definitions(DISP_WIDTH=640) + add_compile_definitions(DISP_HEIGHT=480) + else() + add_compile_definitions(DISP_WIDTH=512) + add_compile_definitions(DISP_HEIGHT=342) + endif() + add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) + set(VIDEO_SRC src/video_vga.c) endif() add_compile_definitions(PIN_USB_HOST_DP=${PIN_USB_HOST_DP}) @@ -132,6 +133,12 @@ add_compile_definitions(PIN_USB_HOST_DM=${PIN_USB_HOST_DM}) add_compile_definitions(PICO_DEFAULT_PIO_USB_DP_PIN=${PIN_USB_HOST_DP}) add_compile_definitions(PICO_DEFAULT_PIO_USB_DM_PIN=${PIN_USB_HOST_DM}) +if (USE_PSRAM) + add_compile_definitions(PIN_PSRAM_CS=${PSRAM_CS} USE_PSRAM=1) +else() + add_compile_definitions(USE_PSRAM=0) +endif() + if (TARGET tinyusb_device) add_executable(firmware src/main.c diff --git a/src/main.c b/src/main.c index 3418a03..04fdf1c 100644 --- a/src/main.c +++ b/src/main.c @@ -53,6 +53,10 @@ #include "hw_config.h" #endif +#if USE_PSRAM +#include "hardware/structs/qmi.h" +#include "hardware/structs/xip.h" +#endif //////////////////////////////////////////////////////////////////////////////// // Imports and data @@ -69,7 +73,12 @@ static const uint8_t umac_rom[] = { #include "umac-rom.h" }; +#if USE_PSRAM +static uint32_t umac_framebuffer_mirror[640*480/32]; +#define umac_ram ((uint8_t*)0x15000000) +#else static uint8_t umac_ram[RAM_SIZE]; +#endif //////////////////////////////////////////////////////////////////////////////// @@ -97,6 +106,27 @@ static int umac_cursor_x = 0; static int umac_cursor_y = 0; static int umac_cursor_button = 0; +#if USE_PSRAM +static void copy_framebuffer() { +#if DISP_WIDTH==640 && DISP_HEIGHT==480 + uint32_t *src = (uint32_t*)(umac_ram + umac_get_fb_offset()), *dest = umac_framebuffer_mirror; + for(int i=0; i<640*480/32; i++) { + *dest++ = *src++ ^ 0xfffffffful; + } +#elif DISP_WIDTH==512 && DISP_HEIGHT==384 + uint32_t *src = umac_ram + umac_get_fb_offset(); + for(i=0; i<384; i++) { + uint32_t *dest = umac_framebuffer_mirror + 962 + 20 * i; + for(j=0; j<16; i++) { + *dest++ = *src++ ^ 0xfffffffful; + } + } +#else +#error Unsupported display geometry +#endif +} +#endif + static void poll_umac() { static absolute_time_t last_1hz = 0; @@ -108,6 +138,9 @@ 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) { +#if USE_PSRAM + copy_framebuffer(); +#endif /* FIXME: Trigger this off actual vsync */ umac_vsync_event(); last_vsync = now; @@ -251,11 +284,16 @@ static void core1_main() printf("Core 1 started\n"); disc_setup(discs); +#if USE_PSRAM + umac_init(umac_ram, (void *)umac_rom, discs); + video_init((uint32_t *)(umac_framebuffer_mirror)); +#else umac_init(umac_ram, (void *)umac_rom, discs); /* Video runs on core 1, i.e. IRQs/DMA are unaffected by * core 0's USB activity. */ video_init((uint32_t *)(umac_ram + umac_get_fb_offset())); +#endif printf("Enjoyable Mac times now begin:\n\n"); @@ -264,10 +302,155 @@ static void core1_main() } } +size_t psram_size; + +size_t _psram_size; +static void __no_inline_not_in_flash_func(setup_psram)(void) { + _psram_size = 0; +#if USE_PSRAM + gpio_set_function(PIN_PSRAM_CS, GPIO_FUNC_XIP_CS1); + uint32_t save = save_and_disable_interrupts(); + // Try and read the PSRAM ID via direct_csr. + qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB | + QMI_DIRECT_CSR_EN_BITS; + // Need to poll for the cooldown on the last XIP transfer to expire + // (via direct-mode BUSY flag) before it is safe to perform the first + // direct-mode operation + while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { + } + + // Exit out of QMI in case we've inited already + qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS; + // Transmit as quad. + qmi_hw->direct_tx = QMI_DIRECT_TX_OE_BITS | + QMI_DIRECT_TX_IWIDTH_VALUE_Q << QMI_DIRECT_TX_IWIDTH_LSB | + 0xf5; + while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { + } + (void)qmi_hw->direct_rx; + qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS); + + // Read the id + qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS; + uint8_t kgd = 0; + uint8_t eid = 0; + for (size_t i = 0; i < 7; i++) { + if (i == 0) { + qmi_hw->direct_tx = 0x9f; + } else { + qmi_hw->direct_tx = 0xff; + } + while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_TXEMPTY_BITS) == 0) { + } + while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { + } + if (i == 5) { + kgd = qmi_hw->direct_rx; + } else if (i == 6) { + eid = qmi_hw->direct_rx; + } else { + (void)qmi_hw->direct_rx; + } + } + // Disable direct csr. + qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS); + + if (kgd != 0x5D) { + restore_interrupts(save); + return; + } + + // Enable quad mode. + qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB | + QMI_DIRECT_CSR_EN_BITS; + // Need to poll for the cooldown on the last XIP transfer to expire + // (via direct-mode BUSY flag) before it is safe to perform the first + // direct-mode operation + while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { + } + + // RESETEN, RESET and quad enable + for (uint8_t i = 0; i < 3; i++) { + qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS; + if (i == 0) { + qmi_hw->direct_tx = 0x66; + } else if (i == 1) { + qmi_hw->direct_tx = 0x99; + } else { + qmi_hw->direct_tx = 0x35; + } + while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) { + } + qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS); + for (size_t j = 0; j < 20; j++) { + asm ("nop"); + } + (void)qmi_hw->direct_rx; + } + // Disable direct csr. + qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS); + + qmi_hw->m[1].timing = + QMI_M0_TIMING_PAGEBREAK_VALUE_1024 << QMI_M0_TIMING_PAGEBREAK_LSB | // Break between pages. + 3 << QMI_M0_TIMING_SELECT_HOLD_LSB | // Delay releasing CS for 3 extra system cycles. + 1 << QMI_M0_TIMING_COOLDOWN_LSB | + 1 << QMI_M0_TIMING_RXDELAY_LSB | + 16 << QMI_M0_TIMING_MAX_SELECT_LSB | // In units of 64 system clock cycles. PSRAM says 8us max. 8 / 0.00752 / 64 = 16.62 + 7 << QMI_M0_TIMING_MIN_DESELECT_LSB | // In units of system clock cycles. PSRAM says 50ns.50 / 7.52 = 6.64 + 2 << QMI_M0_TIMING_CLKDIV_LSB; + qmi_hw->m[1].rfmt = (QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB | + QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_RFMT_ADDR_WIDTH_LSB | + QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_SUFFIX_WIDTH_LSB | + QMI_M0_RFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_RFMT_DUMMY_WIDTH_LSB | + QMI_M0_RFMT_DUMMY_LEN_VALUE_24 << QMI_M0_RFMT_DUMMY_LEN_LSB | + QMI_M0_RFMT_DATA_WIDTH_VALUE_Q << QMI_M0_RFMT_DATA_WIDTH_LSB | + QMI_M0_RFMT_PREFIX_LEN_VALUE_8 << QMI_M0_RFMT_PREFIX_LEN_LSB | + QMI_M0_RFMT_SUFFIX_LEN_VALUE_NONE << QMI_M0_RFMT_SUFFIX_LEN_LSB); + qmi_hw->m[1].rcmd = 0xeb << QMI_M0_RCMD_PREFIX_LSB | + 0 << QMI_M0_RCMD_SUFFIX_LSB; + qmi_hw->m[1].wfmt = (QMI_M0_WFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_PREFIX_WIDTH_LSB | + QMI_M0_WFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_WFMT_ADDR_WIDTH_LSB | + QMI_M0_WFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_SUFFIX_WIDTH_LSB | + QMI_M0_WFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_WFMT_DUMMY_WIDTH_LSB | + QMI_M0_WFMT_DUMMY_LEN_VALUE_NONE << QMI_M0_WFMT_DUMMY_LEN_LSB | + QMI_M0_WFMT_DATA_WIDTH_VALUE_Q << QMI_M0_WFMT_DATA_WIDTH_LSB | + QMI_M0_WFMT_PREFIX_LEN_VALUE_8 << QMI_M0_WFMT_PREFIX_LEN_LSB | + QMI_M0_WFMT_SUFFIX_LEN_VALUE_NONE << QMI_M0_WFMT_SUFFIX_LEN_LSB); + qmi_hw->m[1].wcmd = 0x38 << QMI_M0_WCMD_PREFIX_LSB | + 0 << QMI_M0_WCMD_SUFFIX_LSB; + + restore_interrupts(save); + + _psram_size = 1024 * 1024; // 1 MiB + uint8_t size_id = eid >> 5; + if (eid == 0x26 || size_id == 2) { + _psram_size *= 8; + } else if (size_id == 0) { + _psram_size *= 2; + } else if (size_id == 1) { + _psram_size *= 4; + } + + // Mark that we can write to PSRAM. + xip_ctrl_hw->ctrl |= XIP_CTRL_WRITABLE_M1_BITS; + + // Test write to the PSRAM. + volatile uint32_t *psram_nocache = (volatile uint32_t *)0x15000000; + psram_nocache[0] = 0x12345678; + volatile uint32_t readback = psram_nocache[0]; + if (readback != 0x12345678) { + _psram_size = 0; + return; + } +#endif +} + int main() { // set_sys_clock_khz(250*1000, true); + setup_psram(); + stdio_init_all(); io_init(); @@ -278,17 +461,15 @@ int main() pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; pio_cfg.tx_ch = 2; pio_cfg.pin_dp = PICO_DEFAULT_PIO_USB_DP_PIN; - -//#ifdef PICO_DEFAULT_PIO_USB_VBUSEN_PIN - gpio_init(PICO_DEFAULT_PIO_USB_VBUSEN_PIN); - gpio_set_dir(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, GPIO_OUT); - gpio_put(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, PICO_DEFAULT_PIO_USB_VBUSEN_STATE); -//#endif - -#if 0 _Static_assert(PIN_USB_HOST_DP + 1 == PIN_USB_HOST_DM || PIN_USB_HOST_DP - 1 == PIN_USB_HOST_DM, "Permitted USB D+/D- configuration"); pio_cfg.pinout = PIN_USB_HOST_DP + 1 == PIN_USB_HOST_DM ? PIO_USB_PINOUT_DPDM : PIO_USB_PINOUT_DMDP; + +#ifdef PICO_DEFAULT_PIO_USB_VBUSEN_PIN + gpio_init(PICO_DEFAULT_PIO_USB_VBUSEN_PIN); + gpio_set_dir(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, GPIO_OUT); + gpio_put(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, PICO_DEFAULT_PIO_USB_VBUSEN_STATE); #endif + tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg); tuh_init(BOARD_TUH_RHPORT); From ada575fe01f96a6c2d9a848fe490b356bf3fc444 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Mar 2025 20:32:43 -0500 Subject: [PATCH 19/55] Support 512x342 with hstx when mirroring from psram --- CMakeLists.txt | 27 ++++++++++++--------------- fetch-rom-dsk.sh | 2 ++ src/main.c | 18 +++++++++++------- src/video_hstx.c | 10 ++++++---- 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa79eb2..28b4723 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,10 +46,10 @@ option(USE_HSTX "Use HSTX digital video (only for rp2350 / pico2)" OFF) # Options for HSTX output (defaults are for Adafruit FruitJam) # HSTX always uses 640x480 for now -set(HSTX_CKP 12 CACHE STRING "HSTX CK+ PIN") -set(HSTX_D0P 14 CACHE STRING "HSTX D0+ PIN") -set(HSTX_D1P 16 CACHE STRING "HSTX D1+ PIN") -set(HSTX_D2P 18 CACHE STRING "HSTX D2+ PIN") +set(HSTX_CKP 13 CACHE STRING "HSTX CK+ PIN") +set(HSTX_D0P 15 CACHE STRING "HSTX D0+ PIN") +set(HSTX_D1P 17 CACHE STRING "HSTX D1+ PIN") +set(HSTX_D2P 19 CACHE STRING "HSTX D2+ PIN") # Options for analog VGA output option(USE_VGA_RES "Video uses VGA (640x480) resolution" OFF) @@ -110,23 +110,20 @@ endif() if (USE_HSTX) add_compile_definitions(USE_VGA_RES=1) - add_compile_definitions(DISP_WIDTH=640) - add_compile_definitions(DISP_HEIGHT=480) add_compile_definitions(HSTX_CKP=${HSTX_CKP} HSTX_D0P=${HSTX_D0P} HSTX_D1P=${HSTX_D1P} HSTX_D2P=${HSTX_D2P}) set(VIDEO_SRC src/video_hstx.c) else() - if (USE_VGA_RES) - add_compile_definitions(USE_VGA_RES=1) - add_compile_definitions(DISP_WIDTH=640) - add_compile_definitions(DISP_HEIGHT=480) - else() - add_compile_definitions(DISP_WIDTH=512) - add_compile_definitions(DISP_HEIGHT=342) - endif() - add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) set(VIDEO_SRC src/video_vga.c) endif() +if (USE_VGA_RES) + add_compile_definitions(USE_VGA_RES=1) + add_compile_definitions(DISP_WIDTH=640) + add_compile_definitions(DISP_HEIGHT=480) +else() + add_compile_definitions(DISP_WIDTH=512) + add_compile_definitions(DISP_HEIGHT=342) +endif() add_compile_definitions(PIN_USB_HOST_DP=${PIN_USB_HOST_DP}) add_compile_definitions(PIN_USB_HOST_DM=${PIN_USB_HOST_DM}) diff --git a/fetch-rom-dsk.sh b/fetch-rom-dsk.sh index 75a2511..b0b67b3 100644 --- a/fetch-rom-dsk.sh +++ b/fetch-rom-dsk.sh @@ -5,6 +5,8 @@ if ! [ -f rom.bin ]; then if ! [ -f '4D1F8172 - MacPlus v3.ROM' ]; then curl -L 'https://ia902205.us.archive.org/view_archive.php?archive=/18/items/mac_rom_archive_-_as_of_8-19-2011/mac_rom_archive_-_as_of_8-19-2011.zip&file=4D1F8172%20-%20MacPlus%20v3.ROM' > '4D1F8172 - MacPlus v3.ROM' fi + make -C external/umac clean + make -C external/umac DISP_WIDTH=512 DISP_HEIGHT=342 ./external/umac/main -r '4D1F8172 - MacPlus v3.ROM' -W rom.bin fi diff --git a/src/main.c b/src/main.c index 04fdf1c..7b64830 100644 --- a/src/main.c +++ b/src/main.c @@ -108,21 +108,25 @@ static int umac_cursor_button = 0; #if USE_PSRAM static void copy_framebuffer() { + uint32_t *src = (uint32_t*)(umac_ram + umac_get_fb_offset()); #if DISP_WIDTH==640 && DISP_HEIGHT==480 - uint32_t *src = (uint32_t*)(umac_ram + umac_get_fb_offset()), *dest = umac_framebuffer_mirror; + uint32_t *dest = umac_framebuffer_mirror; for(int i=0; i<640*480/32; i++) { *dest++ = *src++ ^ 0xfffffffful; } -#elif DISP_WIDTH==512 && DISP_HEIGHT==384 - uint32_t *src = umac_ram + umac_get_fb_offset(); - for(i=0; i<384; i++) { - uint32_t *dest = umac_framebuffer_mirror + 962 + 20 * i; - for(j=0; j<16; i++) { +#elif DISP_WIDTH==512 && DISP_HEIGHT==342 + #define DISP_XOFFSET ((640 - DISP_WIDTH) / 32 / 2) + #define DISP_YOFFSET ((480 - DISP_HEIGHT) / 2) + #define LONGS_PER_INPUT_ROW (DISP_WIDTH / 32) + #define LONGS_PER_OUTPUT_ROW (640 / 32) + for(int i=0; ial3_read_addr_trig = (uintptr_t)active_picodvi->dma_commands; } -#if DISP_WIDTH != 640 || DISP_HEIGHT != 480 -#error Only VGA resolution is supported +#if (DISP_WIDTH != 640 || DISP_HEIGHT != 480) && !USE_PSRAM +#error Only VGA resolution is supported without PSRAM #endif +#define REAL_DISP_WIDTH 640 +#define REAL_DISP_HEIGHT 480 void video_init(uint32_t *framebuffer) { picodvi_framebuffer_obj_t *self = &picodvi; @@ -164,7 +166,7 @@ void video_init(uint32_t *framebuffer) { self->dma_command_channel = dma_claim_unused_channel(true); size_t pixels_per_word = 32; - size_t words_per_line = DISP_WIDTH / pixels_per_word; + size_t words_per_line = REAL_DISP_WIDTH / pixels_per_word; uint8_t rot = 24; // 24 + color_depth; size_t shift_amount = 31; // color_depth % 32; @@ -211,7 +213,7 @@ void video_init(uint32_t *framebuffer) { size_t row = v_scanline - active_start; size_t transfer_count = words_per_line; self->dma_commands[command_word++] = transfer_count; - uintptr_t row_start = row * (DISP_WIDTH / 8) + (uintptr_t)framebuffer; + uintptr_t row_start = row * (REAL_DISP_WIDTH / 8) + (uintptr_t)framebuffer; self->dma_commands[command_word++] = row_start; } } From 12541110049179d84a8e28cbefcb4192c475a36c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 18 Mar 2025 13:41:37 -0500 Subject: [PATCH 20/55] a script to build on fruitjam Some configurations that actually work at the time I committed this: ./fruitjam-build.sh -v # vga resolution, no psram, 128KiB ./fruitjam-build.sh -v -m448 # vga resolution, no psram, 448KiB ./fruitjam-build.sh -m4096 # 512x342 resolution, psram, 4096KiB --- fruitjam-build.sh | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100755 fruitjam-build.sh diff --git a/fruitjam-build.sh b/fruitjam-build.sh new file mode 100755 index 0000000..6bb594c --- /dev/null +++ b/fruitjam-build.sh @@ -0,0 +1,58 @@ +#!/bin/sh +set -e + +# Some configurations that actually work at the time I committed this: +# ./fruitjam-build.sh -v # vga resolution, no psram, 128KiB +# ./fruitjam-build.sh -v -m448 # vga resolution, no psram, 448KiB +# ./fruitjam-build.sh -m4096 # 512x342 resolution, psram, 4096KiB + +DISP_WIDTH=512 +DISP_HEIGHT=342 +MEMSIZE=128 +CMAKE_ARGS= + +while getopts "hvm:" o; do + case "$o" in + (v) + DISP_WIDTH=640 + DISP_HEIGHT=480 + CMAKE_ARGS="$CMAKE_ARGS -DUSE_VGA_RES=1 -DHSTX_CKP=12 -DHSTX_D0P=14 -DHSTX_D1P=16 -DHSTX_D2P=18" + ;; + (m) + MEMSIZE=$OPTARG + ;; + (h|?) + echo "Usage: $0 [-v] [-m KiB]" + echo "" + echo " -v: Use framebuffer resolution 640x480 instead of 512x342" + echo " -m: Set memory size in KiB" + echo "" + echo "PSRAM is automatically set depending on memory & framebuffer details" + exit + ;; + esac +done + +TAG=fruitjam_${DISP_WIDTH}x${DISP_HEIGHT}_${MEMSIZE}k +PSRAM=$((MEMSIZE > 448 || DISP_WIDTH != 640)) +if [ $PSRAM -ne 0 ] ; then + TAG=${TAG}_psram + CMAKE_ARGS="$CMAKE_ARGS -DUSE_PSRAM=1" +fi + +set -x +make -C external/umac clean +make -C external/umac DISP_WIDTH=${DISP_WIDTH} DISP_HEIGHT=${DISP_HEIGHT} MEMSIZE=${MEMSIZE} +rm -f rom.bin +./external/umac/main -r '4D1F8172 - MacPlus v3.ROM' -W rom.bin || true +[ -f rom.bin ] +xxd -i < rom.bin > incbin/umac-rom.h +rm -rf build_${TAG} +cmake -S . -B build_${TAG} \ + -DPICO_SDK_PATH=../pico-sdk \ + -DBOARD=adafruit_fruit_jam -DPICO_BOARD=pico2 \ + -DMEMSIZE=${MEMSIZE} \ + -DUSE_HSTX=1 \ + -DSD_TX=35 -DSD_RX=36 -DSD_SCK=34 -DSD_CS=39 -DUSE_SD=1 \ + ${CMAKE_ARGS} +make -C build_${TAG} -j$(nproc) From a5e4afc98a67578b24e04e71a8b2b14e8ecd9c0d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 18 Mar 2025 13:56:42 -0500 Subject: [PATCH 21/55] use cached psram access --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 7b64830..ced093c 100644 --- a/src/main.c +++ b/src/main.c @@ -75,7 +75,7 @@ static const uint8_t umac_rom[] = { #if USE_PSRAM static uint32_t umac_framebuffer_mirror[640*480/32]; -#define umac_ram ((uint8_t*)0x15000000) +#define umac_ram ((uint8_t*)0x11000000) #else static uint8_t umac_ram[RAM_SIZE]; #endif From 6dce5594c5899157ea12119ed4d3c00998e0cf00 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 18 Mar 2025 14:06:35 -0500 Subject: [PATCH 22/55] show audio buffer next to screen in 512x342 --- src/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main.c b/src/main.c index ced093c..16050ce 100644 --- a/src/main.c +++ b/src/main.c @@ -106,6 +106,7 @@ static int umac_cursor_x = 0; static int umac_cursor_y = 0; static int umac_cursor_button = 0; +#define umac_get_audio_offset() (RAM_SIZE - 768) #if USE_PSRAM static void copy_framebuffer() { uint32_t *src = (uint32_t*)(umac_ram + umac_get_fb_offset()); @@ -125,6 +126,11 @@ 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 From 0753cef012ea37a93bfd06a4d624319c7a86a164 Mon Sep 17 00:00:00 2001 From: ladyada Date: Wed, 19 Mar 2025 09:39:46 -0500 Subject: [PATCH 23/55] Add ability to specify disk image to fruitjam-build --- fruitjam-build.sh | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/fruitjam-build.sh b/fruitjam-build.sh index 6bb594c..afeae76 100755 --- a/fruitjam-build.sh +++ b/fruitjam-build.sh @@ -5,13 +5,15 @@ set -e # ./fruitjam-build.sh -v # vga resolution, no psram, 128KiB # ./fruitjam-build.sh -v -m448 # vga resolution, no psram, 448KiB # ./fruitjam-build.sh -m4096 # 512x342 resolution, psram, 4096KiB +# ./fruitjam-build.sh -d disk.img # specify disk image DISP_WIDTH=512 DISP_HEIGHT=342 -MEMSIZE=128 +MEMSIZE=400 +DISK_IMAGE="" CMAKE_ARGS= -while getopts "hvm:" o; do +while getopts "hvd:m:" o; do case "$o" in (v) DISP_WIDTH=640 @@ -21,11 +23,15 @@ while getopts "hvm:" o; do (m) MEMSIZE=$OPTARG ;; + (d) + DISK_IMAGE=$OPTARG + ;; (h|?) - echo "Usage: $0 [-v] [-m KiB]" + echo "Usage: $0 [-v] [-m KiB] [-d diskimage]" echo "" echo " -v: Use framebuffer resolution 640x480 instead of 512x342" echo " -m: Set memory size in KiB" + echo " -d: Specify disk image to include" echo "" echo "PSRAM is automatically set depending on memory & framebuffer details" exit @@ -34,12 +40,19 @@ while getopts "hvm:" o; do done TAG=fruitjam_${DISP_WIDTH}x${DISP_HEIGHT}_${MEMSIZE}k -PSRAM=$((MEMSIZE > 448 || DISP_WIDTH != 640)) +PSRAM=$((MEMSIZE > 448 || DISP_WIDTH > 640)) if [ $PSRAM -ne 0 ] ; then TAG=${TAG}_psram CMAKE_ARGS="$CMAKE_ARGS -DUSE_PSRAM=1" fi +# Append disk name to build directory if disk image is specified +if [ -n "$DISK_IMAGE" ] && [ -f "$DISK_IMAGE" ]; then + # Extract filename without extension + DISK_NAME=$(basename "$DISK_IMAGE" | sed 's/\.[^.]*$//') + TAG=${TAG}_${DISK_NAME} +fi + set -x make -C external/umac clean make -C external/umac DISP_WIDTH=${DISP_WIDTH} DISP_HEIGHT=${DISP_HEIGHT} MEMSIZE=${MEMSIZE} @@ -47,12 +60,15 @@ rm -f rom.bin ./external/umac/main -r '4D1F8172 - MacPlus v3.ROM' -W rom.bin || true [ -f rom.bin ] xxd -i < rom.bin > incbin/umac-rom.h +if [ -n "$DISK_IMAGE" ] && [ -f "$DISK_IMAGE" ]; then + xxd -i < "$DISK_IMAGE" > incbin/umac-disc.h +fi rm -rf build_${TAG} cmake -S . -B build_${TAG} \ -DPICO_SDK_PATH=../pico-sdk \ - -DBOARD=adafruit_fruit_jam -DPICO_BOARD=pico2 \ + -DBOARD=adafruit_fruit_jam -DPICO_BOARD=pimoroni_pico_plus2_rp2350 \ -DMEMSIZE=${MEMSIZE} \ -DUSE_HSTX=1 \ -DSD_TX=35 -DSD_RX=36 -DSD_SCK=34 -DSD_CS=39 -DUSE_SD=1 \ ${CMAKE_ARGS} -make -C build_${TAG} -j$(nproc) +make -C build_${TAG} -j$(nproc) \ No newline at end of file From 59a61155fc47bae5158c8481d82363463cc33b7c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 19 Mar 2025 13:33:44 -0500 Subject: [PATCH 24/55] bump up the umac --- external/umac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/umac b/external/umac index 606f7f7..0be2290 160000 --- a/external/umac +++ b/external/umac @@ -1 +1 @@ -Subproject commit 606f7f75fee8525d4735a0771bf521007115285e +Subproject commit 0be2290d4a2176938925075eb33cfd9b1a50aab6 From e78e12fa7c0597749f96d6dc6b0424abe4d0ef9d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 19 Mar 2025 15:03:42 -0500 Subject: [PATCH 25/55] fix psram-required check --- .gitmodules | 3 +++ external/pico-extras | 1 + fruitjam-build.sh | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) create mode 160000 external/pico-extras diff --git a/.gitmodules b/.gitmodules index 2cfb244..31792d6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "lib/Pico-PIO-USB"] path = lib/Pico-PIO-USB url = https://github.com/tannewt/Pico-PIO-USB +[submodule "external/pico-extras"] + path = external/pico-extras + url = https://github.com/raspberrypi/pico-extras.git diff --git a/external/pico-extras b/external/pico-extras new file mode 160000 index 0000000..f05d4f7 --- /dev/null +++ b/external/pico-extras @@ -0,0 +1 @@ +Subproject commit f05d4f7371802440cadd36744789a26944d950ac diff --git a/fruitjam-build.sh b/fruitjam-build.sh index afeae76..29d0d52 100755 --- a/fruitjam-build.sh +++ b/fruitjam-build.sh @@ -40,7 +40,7 @@ while getopts "hvd:m:" o; do done TAG=fruitjam_${DISP_WIDTH}x${DISP_HEIGHT}_${MEMSIZE}k -PSRAM=$((MEMSIZE > 448 || DISP_WIDTH > 640)) +PSRAM=$((MEMSIZE > 448 || DISP_WIDTH < 640)) if [ $PSRAM -ne 0 ] ; then TAG=${TAG}_psram CMAKE_ARGS="$CMAKE_ARGS -DUSE_PSRAM=1" From a0268b24dafc468135a56f407f7c86ac19fe8ccc Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 19 Mar 2025 15:03:58 -0500 Subject: [PATCH 26/55] share a picotool path --- fruitjam-build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/fruitjam-build.sh b/fruitjam-build.sh index 29d0d52..f3d4784 100755 --- a/fruitjam-build.sh +++ b/fruitjam-build.sh @@ -66,6 +66,7 @@ fi rm -rf build_${TAG} cmake -S . -B build_${TAG} \ -DPICO_SDK_PATH=../pico-sdk \ + -DPICOTOOL_FETCH_FROM_GIT_PATH="$(pwd)/picotool" \ -DBOARD=adafruit_fruit_jam -DPICO_BOARD=pimoroni_pico_plus2_rp2350 \ -DMEMSIZE=${MEMSIZE} \ -DUSE_HSTX=1 \ From 585a3188e9e25777025a0a3a8244434602f6ef4c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 19 Mar 2025 15:04:20 -0500 Subject: [PATCH 27/55] use fruit jam def (requires updated pico-sdk) --- fruitjam-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fruitjam-build.sh b/fruitjam-build.sh index f3d4784..7b0ea16 100755 --- a/fruitjam-build.sh +++ b/fruitjam-build.sh @@ -67,7 +67,7 @@ rm -rf build_${TAG} cmake -S . -B build_${TAG} \ -DPICO_SDK_PATH=../pico-sdk \ -DPICOTOOL_FETCH_FROM_GIT_PATH="$(pwd)/picotool" \ - -DBOARD=adafruit_fruit_jam -DPICO_BOARD=pimoroni_pico_plus2_rp2350 \ + -DBOARD=adafruit_fruit_jam -DPICO_BOARD=adafruit_fruit_jam \ -DMEMSIZE=${MEMSIZE} \ -DUSE_HSTX=1 \ -DSD_TX=35 -DSD_RX=36 -DSD_SCK=34 -DSD_CS=39 -DUSE_SD=1 \ From ef43caead5d84836aa31abe9575d80285d2191ae Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 19 Mar 2025 15:04:25 -0500 Subject: [PATCH 28/55] fix newline --- fruitjam-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fruitjam-build.sh b/fruitjam-build.sh index 7b0ea16..e270dd1 100755 --- a/fruitjam-build.sh +++ b/fruitjam-build.sh @@ -72,4 +72,4 @@ cmake -S . -B build_${TAG} \ -DUSE_HSTX=1 \ -DSD_TX=35 -DSD_RX=36 -DSD_SCK=34 -DSD_CS=39 -DUSE_SD=1 \ ${CMAKE_ARGS} -make -C build_${TAG} -j$(nproc) \ No newline at end of file +make -C build_${TAG} -j$(nproc) From 42cf94e77f477ce4445e71290a80875a94d7e09c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 19 Mar 2025 15:07:12 -0500 Subject: [PATCH 29/55] bump pico-extras --- external/pico-extras | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/pico-extras b/external/pico-extras index f05d4f7..8606fb8 160000 --- a/external/pico-extras +++ b/external/pico-extras @@ -1 +1 @@ -Subproject commit f05d4f7371802440cadd36744789a26944d950ac +Subproject commit 8606fb88057873154f9b6f98a3e52e233cd988d9 From 7fc903760439752a058d6091de4a9f704c4c7901 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 20 Mar 2025 13:10:14 -0500 Subject: [PATCH 30/55] 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; From 3d090e7bee560e3eee30969356c971a1644049f8 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 20 Mar 2025 13:24:13 -0500 Subject: [PATCH 31/55] aha the i2s converter was assuming it got stereo...! --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f273c20..a1a9b1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,7 +143,7 @@ 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) + 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 PICO_AUDIO_I2S_MONO_INPUT=1) set(EXTRA_AUDIO_LIB pico_util_buffer pico_audio pico_audio_i2s) endif() From adc7fcb0aea6376cd0509e1f066628f3afe74518 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 20 Mar 2025 21:21:53 -0500 Subject: [PATCH 32/55] turbocharge mouse movement --- external/umac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/umac b/external/umac index 4dea595..bc6529e 160000 --- a/external/umac +++ b/external/umac @@ -1 +1 @@ -Subproject commit 4dea595da2d3c616a3ac8bb7031191bbeca85b0d +Subproject commit bc6529ea4b017a0fc285fdd049748d71dcb7dd13 From b552b5e84403f91bf555d77f680f2e8d7f2a7a1a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 21 Mar 2025 12:36:19 -0500 Subject: [PATCH 33/55] Put UART stdout on pin A4 @ 115200 baud --- CMakeLists.txt | 14 ++++++++++++++ fruitjam-build.sh | 1 + 2 files changed, 15 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1a9b1e..72a5574 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,10 @@ cmake_minimum_required(VERSION 3.13) set(PICO_TINYUSB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib/tinyusb) set(PIOUSB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib/Pico-PIO-USB) +set(UART_TX CACHE STRING "") +set(UART_RX CACHE STRING "") +set(UART CACHE STRING "") + option(USE_SD "Build in SD support" OFF) set(SD_TX 3 CACHE STRING "SD SPI TX pin") set(SD_RX 4 CACHE STRING "SD SPI RX pin") @@ -133,6 +137,16 @@ add_compile_definitions(PIN_USB_HOST_DM=${PIN_USB_HOST_DM}) add_compile_definitions(PICO_DEFAULT_PIO_USB_DP_PIN=${PIN_USB_HOST_DP}) add_compile_definitions(PICO_DEFAULT_PIO_USB_DM_PIN=${PIN_USB_HOST_DM}) +if (NOT UART STREQUAL "") + add_compile_definitions(PICO_DEFAULT_UART=${UART}) +endif() +if (NOT UART_TX STREQUAL "") + add_compile_definitions(PICO_DEFAULT_UART_TX_PIN=${UART_TX}) +endif() +if (NOT UART_RX STREQUAL "") + add_compile_definitions(PICO_DEFAULT_UART_RX_PIN=${UART_RX}) +endif() + if (USE_PSRAM) add_compile_definitions(PIN_PSRAM_CS=${PSRAM_CS} USE_PSRAM=1) else() diff --git a/fruitjam-build.sh b/fruitjam-build.sh index 5c27d74..9e20a80 100755 --- a/fruitjam-build.sh +++ b/fruitjam-build.sh @@ -73,5 +73,6 @@ 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 \ + -DUART_TX=44 -DUART_RX=45 -DUART=0 \ ${CMAKE_ARGS} "$@" make -C build_${TAG} -j$(nproc) From 202098c88154e3eeee5604069f91abfa0ead6fba Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 21 Mar 2025 12:46:55 -0500 Subject: [PATCH 34/55] fix printing size of disc image on debug uart it's actually an unsigned long long, but we can bet on it actually having a size that fits in 32 bits. --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index d06b5ef..7902641 100644 --- a/src/main.c +++ b/src/main.c @@ -264,7 +264,7 @@ static void disc_setup(disc_descr_t discs[DISC_NUM_DRIVES]) printf(" *** Can't open %s: %s (%d)!\n", disc0_name, FRESULT_str(fr), fr); goto no_sd; } else { - printf(" Opened, size 0x%x\n", f_size(&discfp)); + printf(" Opened, size %d (0x%x)\n", (unsigned)f_size(&discfp), (unsigned)f_size(&discfp)); if (read_only) printf(" (disc is read-only)\n"); discs[0].base = 0; // Means use R/W ops From a45386a81242f41ee96941909e9f13f392d35975 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 10:05:24 -0500 Subject: [PATCH 35/55] bump umac with latest sound stuff --- external/umac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/umac b/external/umac index bc6529e..f827415 160000 --- a/external/umac +++ b/external/umac @@ -1 +1 @@ -Subproject commit bc6529ea4b017a0fc285fdd049748d71dcb7dd13 +Subproject commit f8274158d41f3c8c244206ec00ce31fecf870b07 From f115fd4c06dee4e212f472226070cadac7242bf0 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 10:21:29 -0500 Subject: [PATCH 36/55] point at my own submodule --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 31792d6..fba6ec5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,5 @@ [submodule "external/umac"] - url = https://github.com/evansm7/umac + url = https://github.com/jepler/umac path = external/umac [submodule "external/no-OS-FatFS-SD-SPI-RPi-Pico"] path = external/no-OS-FatFS-SD-SPI-RPi-Pico From 1d4a3caa012ac26f8b71a6d4596b85fac1d5e52f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 10:23:50 -0500 Subject: [PATCH 37/55] set branch in submodule --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index fba6ec5..59ce58a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,7 @@ [submodule "external/umac"] url = https://github.com/jepler/umac path = external/umac + branch = soundemu [submodule "external/no-OS-FatFS-SD-SPI-RPi-Pico"] path = external/no-OS-FatFS-SD-SPI-RPi-Pico url = https://github.com/evansm7/no-OS-FatFS-SD-SPI-RPi-Pico.git From ab1ce3baf7336fb134d6e2b5d440f3f749cd6069 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 10:24:56 -0500 Subject: [PATCH 38/55] bump umac again --- external/umac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/umac b/external/umac index f827415..697c885 160000 --- a/external/umac +++ b/external/umac @@ -1 +1 @@ -Subproject commit f8274158d41f3c8c244206ec00ce31fecf870b07 +Subproject commit 697c8859c6ca60909c4df38f9f67d65a5d3cf05c From 88d31290e3fe40f06ac942b05b507a36e19ffe04 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 10:48:56 -0500 Subject: [PATCH 39/55] re-point pico-extras submodule --- .gitmodules | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 59ce58a..4c0ae40 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,4 +13,5 @@ url = https://github.com/tannewt/Pico-PIO-USB [submodule "external/pico-extras"] path = external/pico-extras - url = https://github.com/raspberrypi/pico-extras.git + url = https://github.com/jepler/pico-extras.git + branch = i2s-audio-rp2350b-high-pins From 4aa502d663a886247d7689de9e5a47cb97b31636 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 11:08:28 -0500 Subject: [PATCH 40/55] can we build it? --- .github/workflows/build.yaml | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/build.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..77379ec --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,49 @@ +name: Build pico-mac + +on: + push: + pull_request: + release: + types: [published] + check_suite: + types: [rerequested] + + +jobs: + bins: + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install ARM GCC + uses: carlosperate/arm-none-eabi-gcc-action@v1 + with: + release: '13.2.Rel1' + + - name: get submodules + run: git submodule update --init --recursive + + - name: get pico-sdk + run: (cd .. && git clone --depth=1 https://github.com/raspberrypi/pico-sdk) + + - name: build targets + run: | + ./fetch-rom-dsk.sh + ./fruitjam-build.sh -m 4096 + ./fruitjam-build.sh -m 400 -v + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: uf2 files + path: build*/*.uf2 + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: elf files + path: build*/*.elf + From a2ce633ec95e21bcf3dac8d0ef33127da4c50d24 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 11:11:59 -0500 Subject: [PATCH 41/55] bump I2S pins up one --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 72a5574..76c67c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,7 @@ 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 PICO_AUDIO_I2S_MONO_INPUT=1) + add_compile_definitions(ENABLE_AUDIO=1 PICO_AUDIO_I2S_PIO=1 PICO_AUDIO_I2S_DMA_IRQ=0 PICO_AUDIO_I2S_DATA_PIN=41 PICO_AUDIO_I2S_CLOCK_PIN_BASE=42 PICO_AUDIO_I2S_MONO_INPUT=1) set(EXTRA_AUDIO_LIB pico_util_buffer pico_audio pico_audio_i2s) endif() From 838614e616e192f0b552f71ac421e514ce3ef1d3 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 11:12:25 -0500 Subject: [PATCH 42/55] executable bit --- fetch-rom-dsk.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 fetch-rom-dsk.sh diff --git a/fetch-rom-dsk.sh b/fetch-rom-dsk.sh old mode 100644 new mode 100755 From 60655771ed0f13c26c14d3addec3c574f86c9dd4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 11:14:17 -0500 Subject: [PATCH 43/55] needs sdl --- .github/workflows/build.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 77379ec..7d131f9 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -23,6 +23,9 @@ jobs: with: release: '13.2.Rel1' + - name: install sdl + run: sudo apt update && sudo apt install -y libsdl2-dev + - name: get submodules run: git submodule update --init --recursive From fe762df50b7f4bfcdc6f612274766c150ae1a37f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 11:18:06 -0500 Subject: [PATCH 44/55] need our bsp file --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7d131f9..2343aae 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -30,7 +30,7 @@ jobs: run: git submodule update --init --recursive - name: get pico-sdk - run: (cd .. && git clone --depth=1 https://github.com/raspberrypi/pico-sdk) + run: (cd .. && git clone --depth=1 https://github.com/adafruit/pico-sdk adafruit-fruit-jam) - name: build targets run: | From 768ea68354fb89744a962f71d7b3c31605e0f552 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 11:20:58 -0500 Subject: [PATCH 45/55] fix getting pico-sdk --- .github/workflows/build.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 2343aae..648018f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -24,13 +24,13 @@ jobs: release: '13.2.Rel1' - name: install sdl - run: sudo apt update && sudo apt install -y libsdl2-dev + run: sudo apt-get update && sudo apt-get install -y eatmydata && sudo eatmydata apt-get install -y libsdl2-dev - name: get submodules run: git submodule update --init --recursive - name: get pico-sdk - run: (cd .. && git clone --depth=1 https://github.com/adafruit/pico-sdk adafruit-fruit-jam) + run: git clone --depth=1 -b adafruit-fruit-jam https://github.com/adafruit/pico-sdk ../pico-sdk - name: build targets run: | From 9d09be90c04ab54a4957445f1267644b4a2b59b6 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 11:32:55 -0500 Subject: [PATCH 46/55] the state of things --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/README.md b/README.md index 19b17e9..aa94369 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,37 @@ # Pico Micro Mac (pico-umac) +v0.21-fruitjam 22 March 2025 + +I (@jepler) have run roughshod across the code, breaking things willy-nilly and adding + * 512x342 & 640x480 digital output on HSTX + * PIO USB + * PSRAM support + * Some Sound support + * To enable that, some VIA timer 2 support + +The two main variants offered are the "400kB" mac with a 640x480 resolution & a +4MB mac with 512x342 resolution (presented centered on a 640x480 display). + +For now, I2S is on pins A1 (data) A2 (LRCK) A3 (bit clock). With any luck it'll be moved to the on-board I2S soon. + +What works? + * System beep + * A fair amount of hypercard, though not playing melodies with 'play "Boing" "a b c"' + * Hypercard 'play "Boing"' does play audio though (as does 'beep') + * Dark Castle including audio + * After Dark screensavers including audio + +What almost works + * Glider was working, but my sound changes made it boot with an error about missing coprocessor?? (appears linked to the timer2 implementation) + +There are artifacts that you can grab from the latest Actions build, at least until they expire. + + +Some good Mac software: + * https://archive.org/details/HyperCardBootSystem7 + * https://archive.org/details/mac_DarkCastle_1_2 + * https://archive.org/details/AfterDark2 + v0.21 20 December 2024 From 0aaa749236270a0f9d0e8b3c4fb63e8c2e58eefb Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 22 Mar 2025 12:33:02 -0500 Subject: [PATCH 47/55] turn off via timer irq for now, it creates problems --- external/umac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/umac b/external/umac index 697c885..ce55830 160000 --- a/external/umac +++ b/external/umac @@ -1 +1 @@ -Subproject commit 697c8859c6ca60909c4df38f9f67d65a5d3cf05c +Subproject commit ce55830a1babd681d0e9a639c9b23f10cd9e3c96 From 5e5deca4e2f0d6c57f7c2154ff01f085e03c47e9 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 24 Mar 2025 08:44:40 -0500 Subject: [PATCH 48/55] transferred to adafruit org --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 4c0ae40..c6ca2f5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,5 @@ [submodule "external/umac"] - url = https://github.com/jepler/umac + url = https://github.com/adafruit/umac path = external/umac branch = soundemu [submodule "external/no-OS-FatFS-SD-SPI-RPi-Pico"] @@ -13,5 +13,5 @@ url = https://github.com/tannewt/Pico-PIO-USB [submodule "external/pico-extras"] path = external/pico-extras - url = https://github.com/jepler/pico-extras.git + url = https://github.com/adafruit/pico-extras.git branch = i2s-audio-rp2350b-high-pins From cd3bb3448280d492ff225dfcb8604dc21a7c14e0 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 24 Mar 2025 09:50:47 -0500 Subject: [PATCH 49/55] Fix inverse video & support 512x342 w/o psram --- fruitjam-build.sh | 12 +++++++++--- src/main.c | 21 ++++++++++++--------- src/video_hstx.c | 4 ---- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/fruitjam-build.sh b/fruitjam-build.sh index 9e20a80..eaee774 100755 --- a/fruitjam-build.sh +++ b/fruitjam-build.sh @@ -11,14 +11,14 @@ DISP_WIDTH=512 DISP_HEIGHT=342 MEMSIZE=400 DISK_IMAGE="" -CMAKE_ARGS= +CMAKE_ARGS="" while getopts "hvd:m:" o; do case "$o" in (v) DISP_WIDTH=640 DISP_HEIGHT=480 - CMAKE_ARGS="$CMAKE_ARGS -DUSE_VGA_RES=1 -DHSTX_CKP=12 -DHSTX_D0P=14 -DHSTX_D1P=16 -DHSTX_D2P=18" + CMAKE_ARGS="-DUSE_VGA_RES=1" ;; (m) MEMSIZE=$OPTARG @@ -42,12 +42,17 @@ done shift $((OPTIND-1)) TAG=fruitjam_${DISP_WIDTH}x${DISP_HEIGHT}_${MEMSIZE}k -PSRAM=$((MEMSIZE > 448 || DISP_WIDTH < 640)) +PSRAM=$((MEMSIZE > 400)) if [ $PSRAM -ne 0 ] ; then TAG=${TAG}_psram CMAKE_ARGS="$CMAKE_ARGS -DUSE_PSRAM=1" fi +MIRROR_FRAMEBUFFER=$((USE_PSRAM || DISP_WIDTH != 640)) +if [ "$MIRROR_FRAMEBUFFER" -eq 0 ]; then + CMAKE_ARGS="$CMAKE_ARGS -DHSTX_CKP=12 -DHSTX_D0P=14 -DHSTX_D1P=16 -DHSTX_D2P=18 " +fi + # Append disk name to build directory if disk image is specified if [ -n "$DISK_IMAGE" ] && [ -f "$DISK_IMAGE" ]; then # Extract filename without extension @@ -74,5 +79,6 @@ cmake -S . -B build_${TAG} \ -DUSE_HSTX=1 \ -DSD_TX=35 -DSD_RX=36 -DSD_SCK=34 -DSD_CS=39 -DUSE_SD=1 \ -DUART_TX=44 -DUART_RX=45 -DUART=0 \ + -DBOARD_FILE=boards/adafruit_fruit_jam.c \ ${CMAKE_ARGS} "$@" make -C build_${TAG} -j$(nproc) diff --git a/src/main.c b/src/main.c index 7902641..9f56db1 100644 --- a/src/main.c +++ b/src/main.c @@ -82,12 +82,16 @@ static const uint8_t umac_rom[] = { }; #if USE_PSRAM -static uint32_t umac_framebuffer_mirror[640*480/32]; #define umac_ram ((uint8_t*)0x11000000) #else static uint8_t umac_ram[RAM_SIZE]; #endif +#define MIRROR_FRAMEBUFFER (USE_PSRAM || DISP_WIDTH != 640) +#if MIRROR_FRAMEBUFFER +static uint32_t umac_framebuffer_mirror[640*480/32]; +#endif + //////////////////////////////////////////////////////////////////////////////// static void io_init() @@ -115,13 +119,13 @@ static int umac_cursor_y = 0; static int umac_cursor_button = 0; #define umac_get_audio_offset() (RAM_SIZE - 768) -#if USE_PSRAM +#if MIRROR_FRAMEBUFFER static void copy_framebuffer() { uint32_t *src = (uint32_t*)(umac_ram + umac_get_fb_offset()); #if DISP_WIDTH==640 && DISP_HEIGHT==480 uint32_t *dest = umac_framebuffer_mirror; for(int i=0; i<640*480/32; i++) { - *dest++ = *src++ ^ 0xfffffffful; + *dest++ = *src++; } #elif DISP_WIDTH==512 && DISP_HEIGHT==342 #define DISP_XOFFSET ((640 - DISP_WIDTH) / 32 / 2) @@ -131,7 +135,7 @@ static void copy_framebuffer() { for(int i=0; ial3_read_addr_trig = (uintptr_t)active_picodvi->dma_commands; } -#if (DISP_WIDTH != 640 || DISP_HEIGHT != 480) && !USE_PSRAM -#error Only VGA resolution is supported without PSRAM -#endif - #define REAL_DISP_WIDTH 640 #define REAL_DISP_HEIGHT 480 From 1d7580c8b56621edf98b30656e4fb1de4bb73d48 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 24 Mar 2025 09:59:21 -0500 Subject: [PATCH 50/55] Move audio to onboard i2s dac --- CMakeLists.txt | 4 +- external/pico-extras | 2 +- src/main.c | 228 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 76c67c0..d463930 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,8 +157,8 @@ 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=41 PICO_AUDIO_I2S_CLOCK_PIN_BASE=42 PICO_AUDIO_I2S_MONO_INPUT=1) - set(EXTRA_AUDIO_LIB pico_util_buffer pico_audio pico_audio_i2s) + add_compile_definitions(ENABLE_AUDIO=1 PICO_AUDIO_I2S_PIO=1 PICO_AUDIO_I2S_DMA_IRQ=0 PICO_AUDIO_I2S_DATA_PIN=24 PICO_AUDIO_I2S_CLOCK_PIN_BASE=25 PICO_AUDIO_I2S_MONO_INPUT=1 PICO_AUDIO_I2S_SWAP_CLOCK=1) + set(EXTRA_AUDIO_LIB pico_util_buffer pico_audio pico_audio_i2s hardware_i2c) endif() if (TARGET tinyusb_device) diff --git a/external/pico-extras b/external/pico-extras index 0b7be7c..c73f2f3 160000 --- a/external/pico-extras +++ b/external/pico-extras @@ -1 +1 @@ -Subproject commit 0b7be7c7fcc6346f6160e96ec73f940a4d403713 +Subproject commit c73f2f3a2b1ef65dc50113a22aadc5a262a92e0f diff --git a/src/main.c b/src/main.c index 9f56db1..81b97b8 100644 --- a/src/main.c +++ b/src/main.c @@ -60,6 +60,7 @@ #if ENABLE_AUDIO #include "pico/audio_i2s.h" +#include "hardware/i2c.h" uint8_t *audio_base; static void audio_setup(); static bool audio_poll(); @@ -512,6 +513,232 @@ int main() } #if ENABLE_AUDIO + +#define I2C_ADDR 0x18 + +void writeRegister(uint8_t reg, uint8_t value) { + char buf[2]; + buf[0] = reg; + buf[1] = value; + int res = i2c_write_timeout_us(i2c0, I2C_ADDR, buf, sizeof(buf), /* nostop */ false, 1000); + if (res != 2) { +printf("res=%d\n", res); + panic("i2c_write_timeout failed: res=%d\n", res); + } + printf("Write Reg: %d = 0x%x\n", reg, value); +} + +uint8_t readRegister(uint8_t reg) { + char buf[1]; + buf[0] = reg; + int res = i2c_write_timeout_us(i2c0, I2C_ADDR, buf, sizeof(buf), /* nostop */ true, 1000); + if (res != 1) { +printf("res=%d\n", res); + panic("i2c_write_timeout failed: res=%d\n", res); + } + res = i2c_read_timeout_us(i2c0, I2C_ADDR, buf, sizeof(buf), /* nostop */ false, 1000); + if (res != 1) { +printf("res=%d\n", res); + panic("i2c_read_timeout failed: res=%d\n", res); + } + uint8_t value = buf[0]; + printf("Read Reg: %d = 0x%x\n", reg, value); + return value; +} + +void modifyRegister(uint8_t reg, uint8_t mask, uint8_t value) { + uint8_t current = readRegister(reg); + printf("Modify Reg: %d = [Before: 0x%x] with mask 0x%x and value 0x%x\n", reg, current, mask, value); + uint8_t new_value = (current & ~mask) | (value & mask); + writeRegister(reg, new_value); +} + +void setPage(uint8_t page) { + printf("Set page %d\n", page); + writeRegister(0x00, page); +} + + +void Wire_begin() { + i2c_init(i2c0, 100000); + gpio_set_function(20, GPIO_FUNC_I2C); + gpio_set_function(21, GPIO_FUNC_I2C); +} + + +static void setup_i2s_dac() { +gpio_init(22); +gpio_set_dir(22, true); +gpio_put(22, true); // allow i2s to come out of reset + + Wire_begin(); + sleep_ms(1000); + + printf("initialize codec\n"); + + // Reset codec + writeRegister(0x01, 0x01); + sleep_ms(10); + + // Interface Control + modifyRegister(0x1B, 0xC0, 0x00); + modifyRegister(0x1B, 0x30, 0x00); + + // Clock MUX and PLL settings + modifyRegister(0x04, 0x03, 0x03); + modifyRegister(0x04, 0x0C, 0x04); + + writeRegister(0x06, 0x20); // PLL J + writeRegister(0x08, 0x00); // PLL D LSB + writeRegister(0x07, 0x00); // PLL D MSB + + modifyRegister(0x05, 0x0F, 0x02); // PLL P/R + modifyRegister(0x05, 0x70, 0x10); + + // DAC/ADC Config + modifyRegister(0x0B, 0x7F, 0x08); // NDAC + modifyRegister(0x0B, 0x80, 0x80); + + modifyRegister(0x0C, 0x7F, 0x02); // MDAC + modifyRegister(0x0C, 0x80, 0x80); + + modifyRegister(0x12, 0x7F, 0x08); // NADC + modifyRegister(0x12, 0x80, 0x80); + + modifyRegister(0x13, 0x7F, 0x02); // MADC + modifyRegister(0x13, 0x80, 0x80); + + // PLL Power Up + modifyRegister(0x05, 0x80, 0x80); + + // Headset and GPIO Config +setPage(1); +modifyRegister(0x2e, 0xFF, 0x0b); +setPage(0); + modifyRegister(0x43, 0x80, 0x80); // Headset Detect + modifyRegister(0x30, 0x80, 0x80); // INT1 Control + modifyRegister(0x33, 0x3C, 0x14); // GPIO1 + + + // DAC Setup + modifyRegister(0x3F, 0xC0, 0xC0); + + // DAC Routing + setPage(1); + modifyRegister(0x23, 0xC0, 0x40); + modifyRegister(0x23, 0x0C, 0x04); + + // DAC Volume Control + setPage(0); + modifyRegister(0x40, 0x0C, 0x00); + writeRegister(0x41, 0x28); // Left DAC Vol + writeRegister(0x42, 0x28); // Right DAC Vol + + // ADC Setup + modifyRegister(0x51, 0x80, 0x80); + modifyRegister(0x52, 0x80, 0x00); + writeRegister(0x53, 0x68); // ADC Volume + + // Headphone and Speaker Setup + setPage(1); + modifyRegister(0x1F, 0xC0, 0xC0); // HP Driver + modifyRegister(0x28, 0x04, 0x04); // HP Left Gain + modifyRegister(0x29, 0x04, 0x04); // HP Right Gain + writeRegister(0x24, 0x0A); // Left Analog HP + writeRegister(0x25, 0x0A); // Right Analog HP + + modifyRegister(0x28, 0x78, 0x40); // HP Left Gain + modifyRegister(0x29, 0x78, 0x40); // HP Right Gain + + // Speaker Amp + modifyRegister(0x20, 0x80, 0x80); + modifyRegister(0x2A, 0x04, 0x04); + modifyRegister(0x2A, 0x18, 0x08); + writeRegister(0x26, 0x0A); + + // Return to page 0 + setPage(0); + + printf("Initialization complete!\n"); + + + // Read all registers for verification + printf("Reading all registers for verification:\n"); + + setPage(0); + readRegister(0x00); // AIC31XX_PAGECTL + readRegister(0x01); // AIC31XX_RESET + readRegister(0x03); // AIC31XX_OT_FLAG + readRegister(0x04); // AIC31XX_CLKMUX + readRegister(0x05); // AIC31XX_PLLPR + readRegister(0x06); // AIC31XX_PLLJ + readRegister(0x07); // AIC31XX_PLLDMSB + readRegister(0x08); // AIC31XX_PLLDLSB + readRegister(0x0B); // AIC31XX_NDAC + readRegister(0x0C); // AIC31XX_MDAC + readRegister(0x0D); // AIC31XX_DOSRMSB + readRegister(0x0E); // AIC31XX_DOSRLSB + readRegister(0x10); // AIC31XX_MINI_DSP_INPOL + readRegister(0x12); // AIC31XX_NADC + readRegister(0x13); // AIC31XX_MADC + readRegister(0x14); // AIC31XX_AOSR + readRegister(0x19); // AIC31XX_CLKOUTMUX + readRegister(0x1A); // AIC31XX_CLKOUTMVAL + readRegister(0x1B); // AIC31XX_IFACE1 + readRegister(0x1C); // AIC31XX_DATA_OFFSET + readRegister(0x1D); // AIC31XX_IFACE2 + readRegister(0x1E); // AIC31XX_BCLKN + readRegister(0x1F); // AIC31XX_IFACESEC1 + readRegister(0x20); // AIC31XX_IFACESEC2 + readRegister(0x21); // AIC31XX_IFACESEC3 + readRegister(0x22); // AIC31XX_I2C + readRegister(0x24); // AIC31XX_ADCFLAG + readRegister(0x25); // AIC31XX_DACFLAG1 + readRegister(0x26); // AIC31XX_DACFLAG2 + readRegister(0x27); // AIC31XX_OFFLAG + readRegister(0x2C); // AIC31XX_INTRDACFLAG + readRegister(0x2D); // AIC31XX_INTRADCFLAG + readRegister(0x2E); // AIC31XX_INTRDACFLAG2 + readRegister(0x2F); // AIC31XX_INTRADCFLAG2 + readRegister(0x30); // AIC31XX_INT1CTRL + readRegister(0x31); // AIC31XX_INT2CTRL + readRegister(0x33); // AIC31XX_GPIO1 + readRegister(0x3C); // AIC31XX_DACPRB + readRegister(0x3D); // AIC31XX_ADCPRB + readRegister(0x3F); // AIC31XX_DACSETUP + readRegister(0x40); // AIC31XX_DACMUTE + readRegister(0x41); // AIC31XX_LDACVOL + readRegister(0x42); // AIC31XX_RDACVOL + readRegister(0x43); // AIC31XX_HSDETECT + readRegister(0x51); // AIC31XX_ADCSETUP + readRegister(0x52); // AIC31XX_ADCFGA + readRegister(0x53); // AIC31XX_ADCVOL + + setPage(1); + readRegister(0x1F); // AIC31XX_HPDRIVER + readRegister(0x20); // AIC31XX_SPKAMP + readRegister(0x21); // AIC31XX_HPPOP + readRegister(0x22); // AIC31XX_SPPGARAMP + readRegister(0x23); // AIC31XX_DACMIXERROUTE + readRegister(0x24); // AIC31XX_LANALOGHPL + readRegister(0x25); // AIC31XX_RANALOGHPR + readRegister(0x26); // AIC31XX_LANALOGSPL + readRegister(0x27); // AIC31XX_RANALOGSPR + readRegister(0x28); // AIC31XX_HPLGAIN + readRegister(0x29); // AIC31XX_HPRGAIN + readRegister(0x2A); // AIC31XX_SPLGAIN + readRegister(0x2B); // AIC31XX_SPRGAIN + readRegister(0x2C); // AIC31XX_HPCONTROL + readRegister(0x2E); // AIC31XX_MICBIAS + readRegister(0x2F); // AIC31XX_MICPGA + readRegister(0x30); // AIC31XX_MICPGAPI + readRegister(0x31); // AIC31XX_MICPGAMI + readRegister(0x32); // AIC31XX_MICPGACM + + setPage(3); + readRegister(0x10); // AIC31XX_TIMERDIVIDER + +} static int volscale; @@ -549,6 +776,7 @@ const struct audio_i2s_config config = { .data_pin = PICO_AUDIO_I2S_DATA_PIN, .clock_pin_base = PICO_AUDIO_I2S_CLOCK_PIN_BASE, + .clock_pin_swapped = true, .pio_sm = 0, .dma_channel = 3 }; From 9f7a3ac7a51f2725cbc58da406776a96b4915550 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 24 Mar 2025 10:02:54 -0500 Subject: [PATCH 51/55] bump sample rate to 22256 this is the "correct" rate based on the original horizontal line rate of the mac plus and is supported on the fruit jam i2s dac --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 81b97b8..e60ca92 100644 --- a/src/main.c +++ b/src/main.c @@ -768,7 +768,7 @@ struct audio_buffer_pool *producer_pool; static audio_format_t audio_format = { .format = AUDIO_BUFFER_FORMAT_PCM_S16, - .sample_freq = 20000, + .sample_freq = 22256, // 60.15Hz*370, rounded up .channel_count = 1, }; From a56610275972678a12ef09b800bb9083e4a95c42 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 24 Mar 2025 10:28:32 -0500 Subject: [PATCH 52/55] add more board configs --- .github/workflows/build.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 648018f..2d1479f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -36,6 +36,8 @@ jobs: run: | ./fetch-rom-dsk.sh ./fruitjam-build.sh -m 4096 + ./fruitjam-build.sh -m 4096 -v + ./fruitjam-build.sh -m 400 ./fruitjam-build.sh -m 400 -v - name: Upload artifact From 5e307d8167b24f204bd07aa3e4481ca1e8bb3adb Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 24 Mar 2025 10:36:21 -0500 Subject: [PATCH 53/55] Give firmwares distinctive names --- CMakeLists.txt | 73 ++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d463930..87af654 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,12 +71,44 @@ set(PIN_AUDIO_PWM 41 CACHE STRING "Pin for PWM audio") # See below, -DMEMSIZE= will configure umac's memory size, # overriding defaults. +set(MEMSIZE 128 CACHE STRING "Memory size, in KB") + +if (USE_HSTX) + add_compile_definitions(USE_VGA_RES=1) + add_compile_definitions(HSTX_CKP=${HSTX_CKP} HSTX_D0P=${HSTX_D0P} HSTX_D1P=${HSTX_D1P} HSTX_D2P=${HSTX_D2P}) + set(VIDEO_SRC src/video_hstx.c) +else() + add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) + set(VIDEO_SRC src/video_vga.c) +endif() + +if (USE_VGA_RES) + add_compile_definitions(USE_VGA_RES=1) + add_compile_definitions(DISP_WIDTH=640) + add_compile_definitions(DISP_HEIGHT=480) + set(RES "640x480") +else() + add_compile_definitions(DISP_WIDTH=512) + add_compile_definitions(DISP_HEIGHT=342) + set(RES "512x342") +endif() + +if (USE_PSRAM) + add_compile_definitions(PIN_PSRAM_CS=${PSRAM_CS} USE_PSRAM=1) + set(OPT_PSRAM "-psram") +else() + add_compile_definitions(USE_PSRAM=0) + set(OPT_PSRAM "") +endif() + +set(FIRMWARE "pico-mac-${PICO_BOARD}-${MEMSIZE}k-${RES}${OPT_PSRAM}") + # initialize the SDK based on PICO_SDK_PATH # note: this must happen before project() include(pico_sdk_import.cmake) -project(firmware) +project(${FIRMWARE}) # initialize the Raspberry Pi Pico SDK pico_sdk_init() @@ -103,9 +135,9 @@ set(UMAC_SOURCES ${UMAC_MUSASHI_PATH}/softfloat/softfloat.c ) -set(MEMSIZE 128 CACHE STRING "Memory size, in KB") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -g3 -O3 -DPICO -DMUSASHI_CNF=\\\"../include/m68kconf.h\\\" -DUMAC_MEMSIZE=${MEMSIZE}") + if (USE_SD) add_compile_definitions(USE_SD=1) set(FF_DISABLE_RTC ${PICO_RP2350}) # RP2350 doesn't have RTC, so disable it @@ -115,23 +147,6 @@ if (USE_SD) add_compile_definitions(SD_TX=${SD_TX} SD_RX=${SD_RX} SD_SCK=${SD_SCK} SD_CS=${SD_CS} SD_MHZ=${SD_MHZ}) endif() -if (USE_HSTX) - add_compile_definitions(USE_VGA_RES=1) - add_compile_definitions(HSTX_CKP=${HSTX_CKP} HSTX_D0P=${HSTX_D0P} HSTX_D1P=${HSTX_D1P} HSTX_D2P=${HSTX_D2P}) - set(VIDEO_SRC src/video_hstx.c) -else() - add_compile_definitions(GPIO_VID_BASE=${VIDEO_PIN}) - set(VIDEO_SRC src/video_vga.c) -endif() -if (USE_VGA_RES) - add_compile_definitions(USE_VGA_RES=1) - add_compile_definitions(DISP_WIDTH=640) - add_compile_definitions(DISP_HEIGHT=480) -else() - add_compile_definitions(DISP_WIDTH=512) - add_compile_definitions(DISP_HEIGHT=342) -endif() - add_compile_definitions(PIN_USB_HOST_DP=${PIN_USB_HOST_DP}) add_compile_definitions(PIN_USB_HOST_DM=${PIN_USB_HOST_DM}) add_compile_definitions(PICO_DEFAULT_PIO_USB_DP_PIN=${PIN_USB_HOST_DP}) @@ -147,12 +162,6 @@ if (NOT UART_RX STREQUAL "") add_compile_definitions(PICO_DEFAULT_UART_RX_PIN=${UART_RX}) endif() -if (USE_PSRAM) - add_compile_definitions(PIN_PSRAM_CS=${PSRAM_CS} USE_PSRAM=1) -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) @@ -162,7 +171,7 @@ if (USE_AUDIO) endif() if (TARGET tinyusb_device) - add_executable(firmware + add_executable(${FIRMWARE} src/main.c ${VIDEO_SRC} src/kbd.c @@ -185,9 +194,9 @@ if (TARGET tinyusb_device) add_custom_target(prepare_umac DEPENDS ${UMAC_MUSASHI_PATH}/m68kops.c ) - add_dependencies(firmware prepare_umac) + add_dependencies(${FIRMWARE} prepare_umac) - target_link_libraries(firmware + target_link_libraries(${FIRMWARE} pico_stdlib pico_multicore tinyusb_host @@ -199,7 +208,7 @@ if (TARGET tinyusb_device) ${EXTRA_AUDIO_LIB} ) - target_include_directories(firmware PRIVATE + target_include_directories(${FIRMWARE} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include ${PICO_TINYUSB_PATH}/hw ${PICO_TINYUSB_PATH}/src @@ -210,13 +219,13 @@ if (TARGET tinyusb_device) ) if (NOT USE_HSTX) - pico_generate_pio_header(firmware ${CMAKE_CURRENT_LIST_DIR}/src/pio_video.pio) + pico_generate_pio_header(${FIRMWARE} ${CMAKE_CURRENT_LIST_DIR}/src/pio_video.pio) endif() - pico_enable_stdio_uart(firmware 1) + pico_enable_stdio_uart(${FIRMWARE} 1) # Needed for UF2: - pico_add_extra_outputs(firmware) + pico_add_extra_outputs(${FIRMWARE}) elseif(PICO_ON_DEVICE) message(WARNING "not building firmware because TinyUSB submodule is not initialized in the SDK") From f02bb8e26053b196d41cd79e1b02c69dcee6db76 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 24 Mar 2025 10:40:02 -0500 Subject: [PATCH 54/55] try to attach files to releases --- .github/workflows/build.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 2d1479f..2018d0f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -52,3 +52,11 @@ jobs: name: elf files path: build*/*.elf + - name: Create release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + files: build*/*.uf2 + fail_on_unmatched_files: true + body: "Select a uf2 from the list below." + From c611126e853bbd6d9e5f81483a24729ac1e2d6ea Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 24 Mar 2025 11:14:53 -0500 Subject: [PATCH 55/55] actually call i2s dac setup code --- src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.c b/src/main.c index e60ca92..4e5bc3a 100644 --- a/src/main.c +++ b/src/main.c @@ -787,6 +787,7 @@ static struct audio_buffer_format producer_format = { }; static void audio_setup() { +setup_i2s_dac(); const struct audio_format *output_format = audio_i2s_setup(&audio_format, &config); assert(output_format); if (!output_format) {