Merge pull request #886 from 32blit/patch-ccache-cache-path

Fix ccache path
diff --git a/32blit-pico/CMakeLists.txt b/32blit-pico/CMakeLists.txt
index 6168e30..28053a1 100644
--- a/32blit-pico/CMakeLists.txt
+++ b/32blit-pico/CMakeLists.txt
@@ -54,7 +54,6 @@
 )
 
 target_compile_definitions(BlitHalPico INTERFACE
-    PICO_AUDIO_I2S_MONO_INPUT=1
     PICO_AUDIO_DMA_IRQ=1
 )
 
@@ -110,10 +109,7 @@
 endif()
 
 # driver dependencies
-if(BLIT_AUDIO_DRIVER STREQUAL "i2s")
-    set(BLIT_REQUIRE_PICO_EXTRAS TRUE)
-    list(APPEND BLIT_BOARD_LIBRARIES pico_audio_i2s)
-elseif(BLIT_AUDIO_DRIVER STREQUAL "pwm")
+if(BLIT_AUDIO_DRIVER STREQUAL "pwm")
     set(BLIT_REQUIRE_PICO_EXTRAS TRUE)
     list(APPEND BLIT_BOARD_LIBRARIES pico_audio_pwm)
 endif()
@@ -150,6 +146,7 @@
 # generate PIO headers (has to be after SDK init)
 pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/dbi-spi.pio)
 pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/dbi-8bit.pio)
+pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/audio/i2s.pio)
 pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/spi.pio)
 
 # include picovision drivers
diff --git a/32blit-pico/audio/i2s.cpp b/32blit-pico/audio/i2s.cpp
index 9a57c48..2548215 100644
--- a/32blit-pico/audio/i2s.cpp
+++ b/32blit-pico/audio/i2s.cpp
@@ -1,89 +1,141 @@
+#include <cmath>
+
 #include "audio.hpp"
 #include "config.h"
 
+#include "hardware/clocks.h"
 #include "hardware/dma.h"
 #include "hardware/pio.h"
-#include "pico/audio_i2s.h"
-#define AUDIO_SAMPLE_FREQ 44100
 
 #include "audio/audio.hpp"
 
-#define audio_pio __CONCAT(pio, PICO_AUDIO_I2S_PIO)
+#include "i2s.pio.h"
 
-static audio_buffer_pool *audio_pool = nullptr;
+#define audio_pio __CONCAT(pio, AUDIO_I2S_PIO)
 
-static struct audio_buffer *cur_buffer = nullptr;
+#define AUDIO_SAMPLE_FREQ 44100
+#define AUDIO_BUFFER_SIZE 256
+#define AUDIO_NUM_BUFFERS 2
+
+static int16_t audio_buffer[AUDIO_BUFFER_SIZE * AUDIO_NUM_BUFFERS];
+static volatile int need_refill = AUDIO_NUM_BUFFERS;
+static int cur_read_buffer_index = 1;
+static int cur_write_buffer_index = 1;
+
+// track offset if we limit samples pre update
+#ifdef AUDIO_MAX_SAMPLE_UPDATE
+static int refill_offset = 0;
+#endif
+
+static const int dma_irq = 1; // we usually use DMA_IRQ_0 for display stuff
+static int dma_channel;
+
+static void __not_in_flash_func(i2s_irq_handler)() {
+  if(!dma_irqn_get_channel_status(dma_irq, dma_channel))
+    return;
+
+  dma_irqn_acknowledge_channel(dma_irq, dma_channel);
+
+  if(need_refill < AUDIO_NUM_BUFFERS - 1)
+    need_refill++;
+
+  // setup for next buffer
+  dma_channel_set_read_addr(dma_channel, audio_buffer + cur_read_buffer_index * AUDIO_BUFFER_SIZE, true);
+
+  cur_read_buffer_index = (cur_read_buffer_index + 1) % AUDIO_NUM_BUFFERS;
+}
 
 void init_audio() {
-  static audio_format_t audio_format = {
-    .sample_freq = AUDIO_SAMPLE_FREQ,
-    .format = AUDIO_BUFFER_FORMAT_PCM_S16,
-    .channel_count = 1
-  };
+  // setup PIO
 
-  static struct audio_buffer_format producer_format = {
-    .format = &audio_format,
-    .sample_stride = 2
-  };
+#if AUDIO_I2S_DATA_PIN >= 32 || AUDIO_I2S_CLOCK_PIN_BASE >= 31
+    // this assumes anything else using this PIO can also deal with the base
+    static_assert(AUDIO_I2S_DATA_PIN >= 16 && AUDIO_I2S_CLOCK_PIN_BASE >= 16);
+    pio_set_gpio_base(audio_pio, 16);
+#endif
 
-  struct audio_buffer_pool *producer_pool = audio_new_producer_pool(&producer_format, 4, 256);
-  const struct audio_format *output_format;
+  int pio_offset = pio_add_program(audio_pio, &i2s_program);
 
-  uint8_t dma_channel = dma_claim_unused_channel(true);
-  uint8_t pio_sm = pio_claim_unused_sm(audio_pio, true);
+  int pio_sm = pio_claim_unused_sm(audio_pio, true);
 
-  // audio_i2s_setup claims
-  dma_channel_unclaim(dma_channel);
-  pio_sm_unclaim(audio_pio, pio_sm);
+  pio_sm_config cfg = i2s_program_get_default_config(pio_offset);
 
-  struct audio_i2s_config config = {
-    .data_pin = PICO_AUDIO_I2S_DATA_PIN,
-    .clock_pin_base = PICO_AUDIO_I2S_CLOCK_PIN_BASE,
-    .dma_channel = dma_channel,
-    .pio_sm = pio_sm,
-  };
+  const int bitrate = AUDIO_SAMPLE_FREQ * 16 * 2;
+  const int clkdiv = clock_get_hz(clk_sys) / float(bitrate * 2);
+  sm_config_set_clkdiv(&cfg, clkdiv);
 
-  output_format = audio_i2s_setup(&audio_format, &config);
-  if (!output_format) {
-    panic("PicoAudio: Unable to open audio device.\n");
-  }
+  sm_config_set_out_shift(&cfg, false, true, 32);
+  sm_config_set_out_pins(&cfg, AUDIO_I2S_DATA_PIN, 1);
+  sm_config_set_fifo_join(&cfg, PIO_FIFO_JOIN_TX);
+  sm_config_set_sideset_pins(&cfg, AUDIO_I2S_CLOCK_PIN_BASE);
 
-  [[maybe_unused]] bool ok = audio_i2s_connect(producer_pool);
-  assert(ok);
-  audio_i2s_set_enabled(true);
+  // init pins
+  pio_gpio_init(audio_pio, AUDIO_I2S_DATA_PIN);
+  pio_gpio_init(audio_pio, AUDIO_I2S_CLOCK_PIN_BASE + 0); // bit clock
+  pio_gpio_init(audio_pio, AUDIO_I2S_CLOCK_PIN_BASE + 1); // left/right clock
 
-  audio_pool = producer_pool;
+  pio_sm_set_consecutive_pindirs(audio_pio, pio_sm, AUDIO_I2S_DATA_PIN, 1, true);
+  pio_sm_set_consecutive_pindirs(audio_pio, pio_sm, AUDIO_I2S_CLOCK_PIN_BASE, 2, true);
+
+  pio_sm_init(audio_pio, pio_sm, pio_offset, &cfg);
+
+  // setup DMA
+  dma_channel = dma_claim_unused_channel(true);
+
+  dma_channel_config c;
+  c = dma_channel_get_default_config(dma_channel);
+  channel_config_set_dreq(&c, pio_get_dreq(audio_pio, pio_sm, true));
+  channel_config_set_transfer_data_size(&c, DMA_SIZE_16); // free mono -> stereo!
+  dma_channel_configure(
+    dma_channel,
+    &c,
+    &audio_pio->txf[pio_sm],
+    audio_buffer,
+    AUDIO_BUFFER_SIZE,
+    false
+  );
+
+  // enable irq
+  dma_irqn_set_channel_enabled(dma_irq, dma_channel, true);
+  irq_add_shared_handler(DMA_IRQ_0 + dma_irq, i2s_irq_handler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
+  irq_set_enabled(DMA_IRQ_0 + dma_irq, true);
+
+  // start
+  dma_channel_start(dma_channel);
+  pio_sm_set_enabled(audio_pio, pio_sm, true);
 }
 
 void update_audio(uint32_t time) {
-  // attempt to get new buffer
-  if(!cur_buffer) {
-    cur_buffer = take_audio_buffer(audio_pool, false);
-    if(cur_buffer)
-      cur_buffer->sample_count = 0;
-  }
+ if(need_refill) {
+  auto buffer = audio_buffer + cur_write_buffer_index * AUDIO_BUFFER_SIZE;
 
-  if(cur_buffer) {
-    auto samples = ((int16_t *)cur_buffer->buffer->bytes) + cur_buffer->sample_count;
-
-    auto max_samples = cur_buffer->max_sample_count - cur_buffer->sample_count;
+  int count = AUDIO_BUFFER_SIZE;
 
 #ifdef AUDIO_MAX_SAMPLE_UPDATE
-    if(max_samples > AUDIO_MAX_SAMPLE_UPDATE)
-      max_samples = AUDIO_MAX_SAMPLE_UPDATE;
+  count -= refill_offset;
+  buffer += refill_offset;
+  if(count > AUDIO_MAX_SAMPLE_UPDATE)
+    count = AUDIO_MAX_SAMPLE_UPDATE;
+
+  refill_offset += count;
 #endif
 
-    for(uint32_t i = 0; i < max_samples; i += 2) {
-      int val = (int)blit::get_audio_frame() - 0x8000;
-      *samples++ = val;
-      *samples++ = val;
-    }
-
-    cur_buffer->sample_count += max_samples;
-
-    if(cur_buffer->sample_count == cur_buffer->max_sample_count) {
-      give_audio_buffer(audio_pool, cur_buffer);
-      cur_buffer = nullptr;
-    }
+  for(int i = 0; i < count; i += 2) {
+    int val = (int)blit::get_audio_frame() - 0x8000;
+    // 22050 -> 44100
+    *buffer++ = val;
+    *buffer++ = val;
   }
+
+#ifdef AUDIO_MAX_SAMPLE_UPDATE
+  if(refill_offset < AUDIO_BUFFER_SIZE)
+    return;
+
+  refill_offset = 0;
+#endif
+
+  cur_write_buffer_index = (cur_write_buffer_index + 1) % AUDIO_NUM_BUFFERS;
+
+  need_refill--;
+ }
 }
diff --git a/32blit-pico/audio/i2s.pio b/32blit-pico/audio/i2s.pio
new file mode 100644
index 0000000..37e7f2d
--- /dev/null
+++ b/32blit-pico/audio/i2s.pio
@@ -0,0 +1,17 @@
+.program i2s
+; sideset bck, lrclk
+.side_set 2
+    set x, 14      side 0b11
+
+; 16 bits for LRCLK=1
+; 2 16-bit values, R is first/highest
+loop1:
+    out pins, 1    side 0b10
+    jmp x--, loop1 side 0b11
+    out pins, 1    side 0b00 ; last bit and switch LRCLK
+    set x, 14      side 0b01 ; prepare for next word
+
+loop0:
+    out pins, 1    side 0b00
+    jmp x--, loop0 side 0b01
+    out pins, 1    side 0b10 ; last bit and switch LRCLK
diff --git a/32blit-pico/board/pimoroni_picovision/config.cmake b/32blit-pico/board/pimoroni_picovision/config.cmake
index c698af7..ac97cdb 100644
--- a/32blit-pico/board/pimoroni_picovision/config.cmake
+++ b/32blit-pico/board/pimoroni_picovision/config.cmake
@@ -1,12 +1,5 @@
 set(BLIT_BOARD_NAME "PicoVision")
 
-set(BLIT_BOARD_DEFINITIONS
-    PICO_AUDIO_I2S_PIO=0
-    PICO_AUDIO_I2S_DATA_PIN=26
-    PICO_AUDIO_I2S_CLOCK_PIN_BASE=27
-    PICO_AUDIO_I2S_BUFFER_SAMPLE_LENGTH=256
-)
-
 blit_driver(audio i2s)
 blit_driver(display picovision)
 blit_driver(input usb_hid)
diff --git a/32blit-pico/board/pimoroni_picovision/config.h b/32blit-pico/board/pimoroni_picovision/config.h
index 7682804..4e3b304 100644
--- a/32blit-pico/board/pimoroni_picovision/config.h
+++ b/32blit-pico/board/pimoroni_picovision/config.h
@@ -1,5 +1,8 @@
 #pragma once
 
+#define AUDIO_I2S_DATA_PIN 26
+#define AUDIO_I2S_CLOCK_PIN_BASE 27
+
 #define DEFAULT_SCREEN_FORMAT PixelFormat::BGR555
 
 // native
@@ -11,4 +14,4 @@
 #define SD_SCK  10
 #define SD_MOSI 11
 #define SD_MISO 12
-#define SD_CS   15
\ No newline at end of file
+#define SD_CS   15
diff --git a/32blit-pico/board/vgaboard/config.cmake b/32blit-pico/board/vgaboard/config.cmake
index 27fcf6c..cc4d244 100644
--- a/32blit-pico/board/vgaboard/config.cmake
+++ b/32blit-pico/board/vgaboard/config.cmake
@@ -1,7 +1,6 @@
 set(BLIT_BOARD_NAME "VGA Board")
 
 set(BLIT_BOARD_DEFINITIONS
-    PICO_AUDIO_I2S_BUFFER_SAMPLE_LENGTH=256
     PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA=1
     PICO_SCANVIDEO_MAX_SCANLINE_BUFFER_WORDS=12
 )
diff --git a/32blit-pico/config.h b/32blit-pico/config.h
index e13bf1d..a5f948d 100644
--- a/32blit-pico/config.h
+++ b/32blit-pico/config.h
@@ -18,6 +18,19 @@
 #endif
 #endif
 
+// default i2s config to values from SDK board
+#ifndef AUDIO_I2S_DATA_PIN
+#define AUDIO_I2S_DATA_PIN PICO_AUDIO_I2S_DATA_PIN
+#endif
+
+#ifndef AUDIO_I2S_CLOCK_PIN_BASE
+#define AUDIO_I2S_CLOCK_PIN_BASE PICO_AUDIO_I2S_CLOCK_PIN_BASE
+#endif
+
+#ifndef AUDIO_I2S_PIO
+#define AUDIO_I2S_PIO 0
+#endif
+
 #ifndef BUTTON_LEFT_PIN
 #define BUTTON_LEFT_PIN -1
 #define BUTTON_LEFT_BI_DECL
diff --git a/32blit-pico/input/usb_hid.cpp b/32blit-pico/input/usb_hid.cpp
index 2ea8f3e..0ebc2d7 100644
--- a/32blit-pico/input/usb_hid.cpp
+++ b/32blit-pico/input/usb_hid.cpp
@@ -55,9 +55,15 @@
 void update_input() {
   using namespace blit;
 
+  if(!hid_keyboard_detected && !hid_gamepad_id) {
+    blit::api_data.buttons = 0;
+    return;
+  }
+
+  uint32_t new_buttons = 0;
+
   // keyboard
   if(hid_keyboard_detected) {
-    uint32_t new_buttons = 0;
 
     for(int i = 0; i < 6; i++) {
       switch(hid_keys[i]) {
@@ -109,8 +115,6 @@
           break;
       }
     }
-
-    api_data.buttons = new_buttons;
   }
 
   if(!hid_gamepad_id)
@@ -121,18 +125,21 @@
   while(mapping->id && mapping->id != hid_gamepad_id)
     mapping++;
 
-  api_data.buttons = dpad_map[hid_hat > 8 ? 8 : hid_hat]
-                   | (hid_buttons & (1 << mapping->left)     ? uint32_t(Button::DPAD_LEFT) : 0)
-                   | (hid_buttons & (1 << mapping->right)    ? uint32_t(Button::DPAD_RIGHT) : 0)
-                   | (hid_buttons & (1 << mapping->up)       ? uint32_t(Button::DPAD_UP) : 0)
-                   | (hid_buttons & (1 << mapping->down)     ? uint32_t(Button::DPAD_DOWN) : 0)
-                   | (hid_buttons & (1 << mapping->a)        ? uint32_t(Button::A) : 0)
-                   | (hid_buttons & (1 << mapping->b)        ? uint32_t(Button::B) : 0)
-                   | (hid_buttons & (1 << mapping->x)        ? uint32_t(Button::X) : 0)
-                   | (hid_buttons & (1 << mapping->y)        ? uint32_t(Button::Y) : 0)
-                   | (hid_buttons & (1 << mapping->menu)     ? uint32_t(Button::MENU) : 0)
-                   | (hid_buttons & (1 << mapping->home)     ? uint32_t(Button::HOME) : 0)
-                   | (hid_buttons & (1 << mapping->joystick) ? uint32_t(Button::JOYSTICK) : 0);
+  new_buttons = new_buttons
+              | dpad_map[hid_hat > 8 ? 8 : hid_hat]
+              | (hid_buttons & (1 << mapping->left)     ? uint32_t(Button::DPAD_LEFT) : 0)
+              | (hid_buttons & (1 << mapping->right)    ? uint32_t(Button::DPAD_RIGHT) : 0)
+              | (hid_buttons & (1 << mapping->up)       ? uint32_t(Button::DPAD_UP) : 0)
+              | (hid_buttons & (1 << mapping->down)     ? uint32_t(Button::DPAD_DOWN) : 0)
+              | (hid_buttons & (1 << mapping->a)        ? uint32_t(Button::A) : 0)
+              | (hid_buttons & (1 << mapping->b)        ? uint32_t(Button::B) : 0)
+              | (hid_buttons & (1 << mapping->x)        ? uint32_t(Button::X) : 0)
+              | (hid_buttons & (1 << mapping->y)        ? uint32_t(Button::Y) : 0)
+              | (hid_buttons & (1 << mapping->menu)     ? uint32_t(Button::MENU) : 0)
+              | (hid_buttons & (1 << mapping->home)     ? uint32_t(Button::HOME) : 0)
+              | (hid_buttons & (1 << mapping->joystick) ? uint32_t(Button::JOYSTICK) : 0);
+
+  api_data.buttons = new_buttons;
 
   api_data.joystick.x = (float(hid_joystick[0]) - 0x80) / 0x80;
   api_data.joystick.y = (float(hid_joystick[1]) - 0x80) / 0x80;
diff --git a/32blit-stm32/CMakeLists.txt b/32blit-stm32/CMakeLists.txt
index 33b1c09..bbab4b0 100644
--- a/32blit-stm32/CMakeLists.txt
+++ b/32blit-stm32/CMakeLists.txt
@@ -1,3 +1,5 @@
+enable_language(ASM)
+
 add_subdirectory(../32blit-shared ../32blit-shared)
 
 add_library(BlitHalSTM32 OBJECT
@@ -107,8 +109,6 @@
 )
 
 set_source_files_properties(
-	startup_stm32h750xx.s
-
 	Src/main.c
   	Src/usbd_msc_scsi.c
 	Src/usb_device.c
diff --git a/32blit-stm32/executable.cmake b/32blit-stm32/executable.cmake
index aee239e..d354838 100644
--- a/32blit-stm32/executable.cmake
+++ b/32blit-stm32/executable.cmake
@@ -1,3 +1,5 @@
+enable_language(ASM)
+
 set(MCU_LINKER_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/${MCU_LINKER_SCRIPT}")
 set(HAL_DIR ${CMAKE_CURRENT_LIST_DIR})
 
@@ -28,7 +30,6 @@
 		return()
 	endif()
 
-	set_source_files_properties(${USER_STARTUP} PROPERTIES LANGUAGE CXX)
 	add_executable(${NAME} ${USER_STARTUP} ${SOURCES})
 
 	# Ideally we want the .blit filename to match the .elf, but TARGET_FILE_BASE_NAME isn't always available
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2abfba3..62ca9dd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.9...3.26)
 
 # has to be before project
 include(32blit-pico/sdk_import.cmake)
diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt
index a367fdc..4118f2e 100644
--- a/firmware/CMakeLists.txt
+++ b/firmware/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.9...3.26)
 project (firmware)
 find_package (32BLIT CONFIG REQUIRED PATHS ..)
 
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index a427f51..592509a 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.9...3.26)
 project (launcher)
 find_package (32BLIT CONFIG REQUIRED PATHS ..)
 
diff --git a/utilities/CMakeLists.txt b/utilities/CMakeLists.txt
index e86ebf1..28badae 100644
--- a/utilities/CMakeLists.txt
+++ b/utilities/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.9...3.26)
 project (examples)
 find_package (32BLIT CONFIG REQUIRED PATHS ..)
 
diff --git a/utilities/hardware-test/CMakeLists.txt b/utilities/hardware-test/CMakeLists.txt
index d76093a..ea3aea6 100644
--- a/utilities/hardware-test/CMakeLists.txt
+++ b/utilities/hardware-test/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.9...3.26)
 project (hardware-test)
 find_package (32BLIT CONFIG REQUIRED PATHS ../..)
 
diff --git a/utilities/picosystem-hardware-test/CMakeLists.txt b/utilities/picosystem-hardware-test/CMakeLists.txt
index ecea602..465ea66 100644
--- a/utilities/picosystem-hardware-test/CMakeLists.txt
+++ b/utilities/picosystem-hardware-test/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.9...3.26)
 project (picosystem-hardware-test)
 find_package (32BLIT CONFIG REQUIRED PATHS ../..)