From e4debd38bccd805b0c4565de7a56113d0ac17fb3 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Sep 2021 09:33:18 +0100 Subject: [PATCH 1/9] pico: PWM audio support for PicoSystem Bring up PWM audio on GPIO 11, pio1 for PicoSystem. This enables audio output for the 32blit audio engine, but the transistor-amplified piezo on PicoSystem is *really* quiet. Music is probably a no-go on this feeble beeper. --- 32blit-pico/CMakeLists.txt | 4 ++++ 32blit-pico/audio.cpp | 47 ++++++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/32blit-pico/CMakeLists.txt b/32blit-pico/CMakeLists.txt index b2402c335..f8cf031f5 100644 --- a/32blit-pico/CMakeLists.txt +++ b/32blit-pico/CMakeLists.txt @@ -45,7 +45,11 @@ if(${PICO_BOARD} STREQUAL "vgaboard") ) elseif(${PICO_BOARD} STREQUAL "pimoroni_picosystem") message("Using picosystem...") + target_link_libraries(BlitHalPico INTERFACE pico_audio_pwm) target_compile_definitions(BlitHalPico INTERFACE + PICO_AUDIO_PWM_PIO=1 + PICO_AUDIO_PWM_MONO_PIN=11 + AUDIO_PWM DISPLAY_ST7789 INPUT_GPIO ) diff --git a/32blit-pico/audio.cpp b/32blit-pico/audio.cpp index 61c461283..804f7668c 100644 --- a/32blit-pico/audio.cpp +++ b/32blit-pico/audio.cpp @@ -3,6 +3,14 @@ #ifdef AUDIO_I2S #include "pico/audio_i2s.h" #define HAVE_AUDIO +#define AUDIO_SAMPLE_FREQ 44100 +#endif + +#ifdef AUDIO_PWM +#include "pico/audio_pwm.h" +#include "hardware/pio.h" +#define HAVE_AUDIO +#define AUDIO_SAMPLE_FREQ 22050 #endif #include "audio/audio.hpp" @@ -12,9 +20,9 @@ static audio_buffer_pool *audio_pool = nullptr; #endif void init_audio() { -#ifdef AUDIO_I2S +#ifdef HAVE_AUDIO static audio_format_t audio_format = { - .sample_freq = 44100, + .sample_freq = AUDIO_SAMPLE_FREQ, .format = AUDIO_BUFFER_FORMAT_PCM_S16, .channel_count = 1 }; @@ -27,6 +35,7 @@ void init_audio() { struct audio_buffer_pool *producer_pool = audio_new_producer_pool(&producer_format, 4, 441); const struct audio_format *output_format; +#ifdef AUDIO_I2S struct audio_i2s_config config = { .data_pin = PICO_AUDIO_I2S_DATA_PIN, .clock_pin_base = PICO_AUDIO_I2S_CLOCK_PIN_BASE, @@ -42,6 +51,29 @@ void init_audio() { bool ok = audio_i2s_connect(producer_pool); assert(ok); audio_i2s_set_enabled(true); +#endif + +#ifdef AUDIO_PWM + struct audio_pwm_channel_config audio_pwm_config = { + .core = { + .base_pin = PICO_AUDIO_PWM_MONO_PIN, + .dma_channel = 1, + .pio_sm = 1, + }, + .pattern = 3, + }; + output_format = audio_pwm_setup(&audio_format, -1, &audio_pwm_config); + if (!output_format) { + panic("PicoAudio: Unable to open audio device.\n"); + } + pio_sm_set_clkdiv(pio1, 1, 2.0f); //! + bool ok = audio_pwm_default_connect(producer_pool, false); + assert(ok); + audio_pwm_set_enabled(true); + gpio_set_drive_strength(PICO_AUDIO_PWM_MONO_PIN, GPIO_DRIVE_STRENGTH_4MA); + gpio_set_slew_rate(PICO_AUDIO_PWM_MONO_PIN, GPIO_SLEW_RATE_FAST); +#endif + audio_pool = producer_pool; #endif } @@ -52,14 +84,21 @@ void update_audio() { struct audio_buffer *buffer = take_audio_buffer(audio_pool, false); if(buffer) { auto samples = (int16_t *) buffer->buffer->bytes; +#ifdef AUDIO_I2S for(uint32_t i = 0; i < buffer->max_sample_count; i += 2) { int val = (int)blit::get_audio_frame() - 0x8000; *samples++ = val; *samples++ = val; } - +#endif +#ifdef AUDIO_PWM + for(uint32_t i = 0; i < buffer->max_sample_count; i++) { + int val = (int)blit::get_audio_frame() - 0x8000; + *samples++ = val; + } +#endif buffer->sample_count = buffer->max_sample_count; give_audio_buffer(audio_pool, buffer); } #endif -} +} \ No newline at end of file From 04a1ffc0659c96456d8cf3c8d682b05f12c18e11 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Sep 2021 15:21:34 +0100 Subject: [PATCH 2/9] engine: fix bug in audio sustain In some cases the ADSR might never decay fully to 0. * If sustain volume is 0, proceed right from decay -> off * Clamp ADSR to sustain volume when sustain phase is triggered --- 32blit/audio/audio.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/32blit/audio/audio.hpp b/32blit/audio/audio.hpp index 7d23d1b07..ae41008ee 100644 --- a/32blit/audio/audio.hpp +++ b/32blit/audio/audio.hpp @@ -104,10 +104,15 @@ namespace blit { adsr_step = (int32_t(sustain << 8) - int32_t(adsr)) / int32_t(adsr_end_frame); } void trigger_sustain() { + if(sustain == 0) { + off(); + return; + } adsr_frame = 0; adsr_phase = ADSRPhase::SUSTAIN; adsr_end_frame = 0; adsr_step = 0; + adsr = int32_t(sustain << 8); } void trigger_release() { adsr_frame = 0; From f6ae08620eeaac59b8b8037c307798d48d9bb3a3 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Sep 2021 15:22:53 +0100 Subject: [PATCH 3/9] pico: fix CMakeLists indentation --- 32blit-pico/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/32blit-pico/CMakeLists.txt b/32blit-pico/CMakeLists.txt index f8cf031f5..b640b82c3 100644 --- a/32blit-pico/CMakeLists.txt +++ b/32blit-pico/CMakeLists.txt @@ -12,14 +12,14 @@ target_sources(BlitHalPico INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ffunicode.c ${CMAKE_CURRENT_LIST_DIR}/audio.cpp - ${CMAKE_CURRENT_LIST_DIR}/file.cpp + ${CMAKE_CURRENT_LIST_DIR}/file.cpp ${CMAKE_CURRENT_LIST_DIR}/input.cpp ${CMAKE_CURRENT_LIST_DIR}/led.cpp ${CMAKE_CURRENT_LIST_DIR}/main.cpp - ${CMAKE_CURRENT_LIST_DIR}/storage.cpp + ${CMAKE_CURRENT_LIST_DIR}/storage.cpp ${CMAKE_CURRENT_LIST_DIR}/st7789.cpp - ${CMAKE_CURRENT_LIST_DIR}/usb.cpp - ${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c + ${CMAKE_CURRENT_LIST_DIR}/usb.cpp + ${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c ) pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/st7789.pio) From 65f0173b103a135df25fa43ddba061b7496e624f Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Sep 2021 15:23:26 +0100 Subject: [PATCH 4/9] pico: add support for naive PWM piezo audio Extract the frequency/duty cycle from the first SQUARE wave channel and route it to PWM on GPIO 11. Run the audio engine to process ADSR phases. Co-authored-by: Charlie Birks --- 32blit-pico/CMakeLists.txt | 6 ++--- 32blit-pico/audio.cpp | 55 ++++++++++++++++++++++++++++++++++++-- 32blit-pico/audio.hpp | 3 ++- 32blit-pico/main.cpp | 2 +- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/32blit-pico/CMakeLists.txt b/32blit-pico/CMakeLists.txt index b640b82c3..f331bca21 100644 --- a/32blit-pico/CMakeLists.txt +++ b/32blit-pico/CMakeLists.txt @@ -45,11 +45,9 @@ if(${PICO_BOARD} STREQUAL "vgaboard") ) elseif(${PICO_BOARD} STREQUAL "pimoroni_picosystem") message("Using picosystem...") - target_link_libraries(BlitHalPico INTERFACE pico_audio_pwm) target_compile_definitions(BlitHalPico INTERFACE - PICO_AUDIO_PWM_PIO=1 - PICO_AUDIO_PWM_MONO_PIN=11 - AUDIO_PWM + AUDIO_BEEP_PIN=11 + AUDIO_BEEP DISPLAY_ST7789 INPUT_GPIO ) diff --git a/32blit-pico/audio.cpp b/32blit-pico/audio.cpp index 804f7668c..bcfd18b56 100644 --- a/32blit-pico/audio.cpp +++ b/32blit-pico/audio.cpp @@ -1,4 +1,5 @@ #include "audio.hpp" +#include "config.h" #ifdef AUDIO_I2S #include "pico/audio_i2s.h" @@ -13,6 +14,17 @@ #define AUDIO_SAMPLE_FREQ 22050 #endif +#ifdef AUDIO_BEEP +#include "hardware/pwm.h" +#include "hardware/clocks.h" +#include "hardware/gpio.h" + +static const uint32_t PWM_WRAP = 65535; +static uint32_t slice_num = 0; +static float clock_hz = 0.0; +static uint32_t beep_time = 0; +#endif + #include "audio/audio.hpp" #ifdef HAVE_AUDIO @@ -20,6 +32,15 @@ static audio_buffer_pool *audio_pool = nullptr; #endif void init_audio() { +#ifdef AUDIO_BEEP + clock_hz = clock_get_hz(clk_sys); + + gpio_set_function(AUDIO_BEEP_PIN, GPIO_FUNC_PWM); + slice_num = pwm_gpio_to_slice_num(AUDIO_BEEP_PIN); + + pwm_set_wrap(slice_num, PWM_WRAP); +#endif + #ifdef HAVE_AUDIO static audio_format_t audio_format = { .sample_freq = AUDIO_SAMPLE_FREQ, @@ -66,7 +87,9 @@ void init_audio() { if (!output_format) { panic("PicoAudio: Unable to open audio device.\n"); } - pio_sm_set_clkdiv(pio1, 1, 2.0f); //! +#if OVERCLOCK_250 + pio_sm_set_clkdiv(pio1, 1, 2.0f); +#endif bool ok = audio_pwm_default_connect(producer_pool, false); assert(ok); audio_pwm_set_enabled(true); @@ -78,7 +101,35 @@ void init_audio() { #endif } -void update_audio() { +void update_audio(uint32_t time) { +#ifdef AUDIO_BEEP + bool on = false; + uint32_t elapsed = time - beep_time; + beep_time = time; + + for(auto f = 0u; f < elapsed * blit::sample_rate / 1000; f++) { + blit::get_audio_frame(); + } + + // Find the first square wave enabled channel and use freq/pulse width to drive the beeper + for(int c = 0; c < CHANNEL_COUNT; c++) { + auto &channel = blit::channels[c]; + + if(channel.waveforms & blit::Waveform::SQUARE) { + on = channel.volume + && channel.adsr_phase != blit::ADSRPhase::RELEASE + && channel.adsr_phase != blit::ADSRPhase::OFF; + + if(on) { + pwm_set_clkdiv(slice_num, (clock_hz / PWM_WRAP) / channel.frequency); + pwm_set_gpio_level(AUDIO_BEEP_PIN, channel.pulse_width); + break; + } + } + } + + pwm_set_enabled(slice_num, on); +#endif #ifdef HAVE_AUDIO // audio struct audio_buffer *buffer = take_audio_buffer(audio_pool, false); diff --git a/32blit-pico/audio.hpp b/32blit-pico/audio.hpp index cf45df167..f5b15acc0 100644 --- a/32blit-pico/audio.hpp +++ b/32blit-pico/audio.hpp @@ -1,4 +1,5 @@ #pragma once +#include void init_audio(); -void update_audio(); +void update_audio(uint32_t time); diff --git a/32blit-pico/main.cpp b/32blit-pico/main.cpp index dfda450a2..a2b17d692 100644 --- a/32blit-pico/main.cpp +++ b/32blit-pico/main.cpp @@ -367,7 +367,7 @@ int main() { #endif update_input(); int ms_to_next_update = tick(::now()); - update_audio(); + update_audio(now); update_led(); update_usb(); From c283d6ce786c54d725a27b62f35c5171626c3b2f Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Sep 2021 19:28:52 +0100 Subject: [PATCH 5/9] Raycaster: Low settings for all Pico builds --- examples/raycaster/raycaster.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/raycaster/raycaster.hpp b/examples/raycaster/raycaster.hpp index 1bf71d28b..b23d0472d 100644 --- a/examples/raycaster/raycaster.hpp +++ b/examples/raycaster/raycaster.hpp @@ -8,7 +8,7 @@ constexpr float M_PI_H = 1.5707963267948966f; constexpr float EPSILON = 0.00000001f; -#ifdef DISPLAY_ST7789 +#ifdef PICO_BOARD constexpr uint16_t OFFSET_TOP = 30; constexpr uint16_t SCREEN_WIDTH = 120; constexpr uint16_t SCREEN_HEIGHT = 120; From bf5688441e8d4e25da2736f5633b9a2f9e130161 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Sep 2021 19:29:09 +0100 Subject: [PATCH 6/9] Geometry: enable SQUARE wave for beep audio --- examples/geometry/geometry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/geometry/geometry.cpp b/examples/geometry/geometry.cpp index 62a254eef..ea345c97b 100644 --- a/examples/geometry/geometry.cpp +++ b/examples/geometry/geometry.cpp @@ -270,7 +270,7 @@ void init() { channels[0].release_ms = 10; channels[0].volume = 4000; - channels[1].waveforms = Waveform::SINE; + channels[1].waveforms = Waveform::SQUARE | Waveform::SINE; channels[1].frequency = 0; channels[1].attack_ms = 10; channels[1].decay_ms = 500; From 9b2d7386281e4128e7c5a95cf4e77ed0906e040d Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 9 Sep 2021 19:33:39 +0100 Subject: [PATCH 7/9] pico: hardware test for PicoSystem Add a hardware test for the RP2040-based PicoSystem. Since the PicoSystem has fewer buttons, no joystick and no tilt it makes more sense to ship a different hardware-test rather than IFDEF the other one to oblivion. --- examples/CMakeLists.txt | 1 + examples/hardware-test/CMakeLists.txt | 6 + .../picosystem-hardware-test/CMakeLists.txt | 11 ++ .../hardware-test-icon.png | Bin 0 -> 1051 bytes .../hardware-test.cpp | 181 ++++++++++++++++++ .../hardware-test.hpp | 1 + .../hardware-test.png | Bin 0 -> 1690 bytes .../picosystem-hardware-test/metadata.yml | 10 + 8 files changed, 210 insertions(+) create mode 100644 examples/picosystem-hardware-test/CMakeLists.txt create mode 100644 examples/picosystem-hardware-test/hardware-test-icon.png create mode 100644 examples/picosystem-hardware-test/hardware-test.cpp create mode 100644 examples/picosystem-hardware-test/hardware-test.hpp create mode 100644 examples/picosystem-hardware-test/hardware-test.png create mode 100644 examples/picosystem-hardware-test/metadata.yml diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index dd2a5cc3d..0903cec54 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(fizzlefade) add_subdirectory(flight) add_subdirectory(geometry) add_subdirectory(hardware-test) +add_subdirectory(picosystem-hardware-test) add_subdirectory(jpeg) add_subdirectory(logo) add_subdirectory(matrix-test) diff --git a/examples/hardware-test/CMakeLists.txt b/examples/hardware-test/CMakeLists.txt index e84622737..3d7a3f9ed 100644 --- a/examples/hardware-test/CMakeLists.txt +++ b/examples/hardware-test/CMakeLists.txt @@ -1,5 +1,11 @@ cmake_minimum_required(VERSION 3.9) project (hardware-test) find_package (32BLIT CONFIG REQUIRED PATHS ../..) + +if(32BLIT_PICO) + # PicoSystem has its own picosystem-hardware-test + return() +endif() + blit_executable (hardware-test hardware-test.cpp) blit_metadata (hardware-test metadata.yml) diff --git a/examples/picosystem-hardware-test/CMakeLists.txt b/examples/picosystem-hardware-test/CMakeLists.txt new file mode 100644 index 000000000..ce7b4b88f --- /dev/null +++ b/examples/picosystem-hardware-test/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.9) +project (picosystem-hardware-test) +find_package (32BLIT CONFIG REQUIRED PATHS ../..) + +if(NOT 32BLIT_PICO) + # Hooks into the Pico SDK to get battery charge and VBUS status + return() +endif() + +blit_executable (picosystem-hardware-test hardware-test.cpp) +blit_metadata (picosystem-hardware-test metadata.yml) \ No newline at end of file diff --git a/examples/picosystem-hardware-test/hardware-test-icon.png b/examples/picosystem-hardware-test/hardware-test-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b2c0a3fa329bea33b56ba46eaba512fc8c58b5ea GIT binary patch literal 1051 zcmbVLy>HV%6t|#5snmgyPKP@{C2XHR;@DP0mDCB1)P#^mYE&Vm7vH6^TKio4N}P(N z2q9Hs;Xi8t$v^JD#(iyN%mW^1&^1}G*%5z{UK)c|dgCP8?(dqNfk;cDWy+N@n$ zbvzo#D6^5%AmV62SX@dYrZoRuKD)MUJ8j1_ODZ%QW6nRNJ-{ zs41EzaSJIKh76@rn9NT+xFqpnKVm)&LFN&4=^iVHoatE#K~$@qI}Vd^p?JxZ6h(?E zLnR2ZyhhduYm&b-F0@Ws!-yzNlF+@_o;qj8JUoyin5`jpY6Pa~kIvIcIi z`yr--WFhO(S;{Vn{YL~>Vj6%^ksbd60y)bxAnrlQ(os%A(9k6d6GOszV&xFZtGc0y zV?6%f;whYzl1<7#lQX&EK0q+=ZA+!vjPx4Z2Vr@xVih{;MtYV)2}b_m*b + +using namespace blit; + +const uint8_t STATUS_V_SPACING = 10; + +const uint32_t VBUS_DETECT_PIN = 2; +const uint32_t CHARGE_STATUS_PIN = 24; + +const int16_t notes[2][384] = { + { // melody notes + 147, 0, 0, 0, 0, 0, 0, 0, 175, 0, 196, 0, 220, 0, 262, 0, 247, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 175, 0, 0, 0, 0, 0, 0, 0, 175, 0, 196, 0, 220, 0, 262, 0, 330, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 349, 0, 330, 0, 294, 0, 220, 0, 262, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, 0, 247, 0, 220, 0, 196, 0, 147, 0, 175, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, + 147, 0, 0, 0, 0, 0, 0, 0, 175, 0, 196, 0, 220, 0, 262, 0, 247, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 175, 0, 0, 0, 0, 0, 0, 0, 175, 0, 196, 0, 220, 0, 262, 0, 330, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 349, 0, 330, 0, 294, 0, 220, 0, 262, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, 0, 247, 0, 220, 0, 196, 0, 147, 0, 175, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, + 147, 0, 0, 0, 0, 0, 0, 0, 175, 0, 196, 0, 220, 0, 262, 0, 247, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 175, 0, 0, 0, 0, 0, 0, 0, 175, 0, 196, 0, 220, 0, 262, 0, 330, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 349, 0, 330, 0, 294, 0, 220, 0, 262, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, 0, 247, 0, 262, 0, 294, 0, 392, 0, 440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + { // rhythm notes + 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 392, 0, 523, 0, 659, 0, 523, 0, 392, 0, 523, 0, 659, 0, 523, 0, 698, 0, 587, 0, 440, 0, 587, 0, 698, 0, 587, 0, 440, 0, 587, 0, 523, 0, 440, 0, 330, 0, 440, 0, 523, 0, 440, 0, 330, 0, 440, 0, 349, 0, 294, 0, 220, 0, 294, 0, 349, 0, 294, 0, 220, 0, 294, 0, 262, 0, 247, 0, 220, 0, 175, 0, 165, 0, 147, 0, 131, 0, 98, 0, + 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 392, 0, 523, 0, 659, 0, 523, 0, 392, 0, 523, 0, 659, 0, 523, 0, 698, 0, 587, 0, 440, 0, 587, 0, 698, 0, 587, 0, 440, 0, 587, 0, 523, 0, 440, 0, 330, 0, 440, 0, 523, 0, 440, 0, 330, 0, 440, 0, 349, 0, 294, 0, 220, 0, 294, 0, 349, 0, 294, 0, 220, 0, 294, 0, 262, 0, 247, 0, 220, 0, 175, 0, 165, 0, 147, 0, 131, 0, 98, 0, + 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 294, 0, 440, 0, 587, 0, 440, 0, 392, 0, 523, 0, 659, 0, 523, 0, 392, 0, 523, 0, 659, 0, 523, 0, 698, 0, 587, 0, 440, 0, 587, 0, 698, 0, 587, 0, 440, 0, 587, 0, 523, 0, 440, 0, 330, 0, 440, 0, 523, 0, 440, 0, 330, 0, 440, 0, 349, 0, 294, 0, 220, 0, 294, 0, 349, 0, 294, 0, 220, 0, 294, 0, 262, 0, 247, 0, 220, 0, 175, 0, 165, 0, 147, 0, 131, 0, 98, 0, + }, +}; + +const Pen LED_COLOUR[3] = { + Pen(255, 0, 0), + Pen(0, 255, 0), + Pen(0, 0, 255) +}; + +uint16_t beat = 0; + +uint32_t been_pressed; + +void init() { + set_screen_mode(ScreenMode::lores); + + gpio_init(VBUS_DETECT_PIN); + gpio_set_dir(VBUS_DETECT_PIN, GPIO_IN); + gpio_init(CHARGE_STATUS_PIN); + gpio_set_dir(CHARGE_STATUS_PIN, GPIO_IN); + + channels[0].waveforms = Waveform::SQUARE; + channels[0].attack_ms = 16; + channels[0].decay_ms = 168; + channels[0].sustain = 0xafff; + channels[0].release_ms = 168; + + channels[1].waveforms = Waveform::SQUARE; + channels[1].attack_ms = 38; + channels[1].decay_ms = 300; + channels[1].sustain = 0; + channels[1].release_ms = 0; +} + +void render(uint32_t time) { + char text_buf[100] = {0}; + bool button_a = buttons & Button::A; + bool button_b = buttons & Button::B; + bool button_x = buttons & Button::X; + bool button_y = buttons & Button::Y; + bool dpad_l = buttons & Button::DPAD_LEFT; + bool dpad_r = buttons & Button::DPAD_RIGHT; + bool dpad_u = buttons & Button::DPAD_UP; + bool dpad_d = buttons & Button::DPAD_DOWN; + + for(int b = 0; b < screen.bounds.w; b++){ + for(int v = 0; v < screen.bounds.h; v++){ + screen.pen = hsv_to_rgba(float(b) / (float)(screen.bounds.w), 1.0f, float(v) / (float)(screen.bounds.h)); + screen.pixel(Point(b, v)); + } + } + + screen.pen = dpad_r ? Pen(255, 0, 0) : Pen(128, 128, 128); + screen.text("R", minimal_font, Point(25, 15), false, center_center); + + screen.pen = dpad_d ? Pen(255, 0, 0) : Pen(128, 128, 128); + screen.text("D", minimal_font, Point(15, 25), false, center_center); + + screen.pen = dpad_u ? Pen(255, 0, 0) : Pen(128, 128, 128); + screen.text("U", minimal_font, Point(15, 5), false, center_center); + + screen.pen = dpad_l ? Pen(255, 0, 0) : Pen(128, 128, 128); + screen.text("L", minimal_font, Point(5, 15), false, center_center); + + screen.pen = button_a ? Pen(255, 0, 0) : Pen(128, 128, 128); + screen.text("A", minimal_font, Point(screen.bounds.w - 5, 15), false, center_center); + + screen.pen = button_b ? Pen(255, 0, 0) : Pen(128, 128, 128); + screen.text("B", minimal_font, Point(screen.bounds.w - 15, 25), false, center_center); + + screen.pen = button_x ? Pen(255, 0, 0) : Pen(128, 128, 128); + screen.text("X", minimal_font, Point(screen.bounds.w - 15, 5), false, center_center); + + screen.pen = button_y ? Pen(255, 0, 0) : Pen(128, 128, 128); + screen.text("Y", minimal_font, Point(screen.bounds.w - 25, 15), false, center_center); + + //LED = hsv_to_rgba(time / 50.0f, 1.0f, 1.0f); + LED = LED_COLOUR[(time / 1000) % 3]; + + Point location(5, screen.bounds.h - (8 * STATUS_V_SPACING)); + std::string label = ""; + + screen.pen = Pen(255, 255, 255); + uint32_t bit = 256; + while(bit > 0) { + bit >>= 1; + switch(bit) { + case Button::A: + label = "A "; + break; + case Button::B: + label = "B "; + break; + case Button::X: + label = "X "; + break; + case Button::Y: + label = "Y "; + break; + case Button::DPAD_UP: + label = "UP "; + break; + case Button::DPAD_DOWN: + label = "DOWN "; + break; + case Button::DPAD_LEFT: + label = "LEFT "; + break; + case Button::DPAD_RIGHT: + label = "RIGHT"; + break; + } + + if (been_pressed & bit) { + label += " OK"; + } + + screen.text(label, minimal_font, location, false); + location.y += STATUS_V_SPACING; + } + + bool charge_status = gpio_get(CHARGE_STATUS_PIN); + bool vbus_connected = gpio_get(VBUS_DETECT_PIN); + + location = Point(screen.bounds.w / 2, screen.bounds.h - (8 * STATUS_V_SPACING)); + + label = "CHG: "; + label += charge_status ? "Yes" : "No"; + screen.text(label, minimal_font, location); + location.y += STATUS_V_SPACING; + + label = "VBUS: "; + label += vbus_connected ? "Yes" : "No"; + screen.text(label, minimal_font, location); +} + +void update(uint32_t time) { + static uint16_t tick = 0; + static uint16_t prev_beat = 1; + + been_pressed |= buttons.pressed; + + beat = (tick / 8) % 384; // 125ms per beat + tick++; + + if (beat == prev_beat) return; + prev_beat = beat; + + for(uint8_t i = 0; i < 2; i++) { + if(notes[i][beat] > 0) { + channels[i].frequency = notes[i][beat]; + channels[i].trigger_attack(); + } else if (notes[i][beat] == -1) { + channels[i].trigger_release(); + } + } +} diff --git a/examples/picosystem-hardware-test/hardware-test.hpp b/examples/picosystem-hardware-test/hardware-test.hpp new file mode 100644 index 000000000..b4df8bd93 --- /dev/null +++ b/examples/picosystem-hardware-test/hardware-test.hpp @@ -0,0 +1 @@ +#include "32blit.hpp" diff --git a/examples/picosystem-hardware-test/hardware-test.png b/examples/picosystem-hardware-test/hardware-test.png new file mode 100644 index 0000000000000000000000000000000000000000..12bb0c7e6aab3087f75651c7e0a36840b5c48717 GIT binary patch literal 1690 zcmaJ?c~BEq9DYeakV1ii1&_+kB5IH%o7=1)xjQYU^%xaPJpeDHqXnd>b*y$o=>`G&N9oS&{@#1@ec$hVvl}!C z^Za}!`2Ya?RP&XIlyy}YGDtgS#evK~q~nmvgk|E1IA(CJ zJcmaEzz8>LQ^*wcLR3$f*q9r`c9<*_8-VCohXvDT<0O=hXBy2h@Wc9(Fl02uz{x^2 zqP8gTEaUtpw;JP>m>#_b}kg{Kq&zePGXS5lw-D`ju?1I7p2zjV-5@rLCEYF z_;pYzY7L|ytT-fMBP>0F@F1~-%@qj*A|wjpAv}bG2svCHiz`AA0m>Ca!w*b(vl=qc zL}mQ2FKQP9XOW}@<#6nFJKN4@6V^-)S0a&c5FUreV^Ii}&1ohv2g_^=A5l=^Hoeto zA&rC?aw}r#L@pTvQ<1(-!DJbgHQR>EL=}wVz$_dt8*!&J0#vL2A8ImzTSjHDCL?c`! zq0cqpW^#mUc*7Ns$#u_y$wGNn;#T8_xFOz3n4qDYQRCRL2*%VK<{HM1MK~sxLj}We zclKYM9yy}M$Gse#TWT{p`M8-HcPlm58#`pV)SU>`EY!wPme1#77*?axEl#e!u-PXR z41&Q(A*-Thz@^`MJ>>4EX%g^VvB%zn0g z-0gLY5{2uocWhA${QPRuv-x0e#98_+e{hPXn+<%`P1D*S5ZYF9$^jTOo-IwGSwDA2 zS7_Qc zg*OV~PNfd0pG1r4h)4GYP4`2|<76Le1P zEDgV>azTAbw7Fdx0?Ow$+)MM5E|Xx)Ys?zo_Jf6<($+agqtYs*-qJl0J8OKP-d#5u zBrX}P?+e!*NfX>GPffy+in87);xc}B zR`9X+bgPQ9%IW>RxgDt=L{@a&sY&_6_rX0y*@MCQdnao*y|~JHdQ-jCX&$FpR>tUV zsP+8j^T5d$-VXRGw>0YasPi4u#Zy{j1wW5Jm%kH0y~RaA$Cm#{_h1DnXChjepUXe+ zXwIbrj7Fo2xuFI1bWNx4&UjpUTEYSrp4T;IkfF-svfNUNo=unx1X|kJguqHKT2?|p v*AISjCwt9CYuKwT?bS(gvBxw1tydnQfJ_TeBlV!${kKrXB`6Qdbw&RGHSutu literal 0 HcmV?d00001 diff --git a/examples/picosystem-hardware-test/metadata.yml b/examples/picosystem-hardware-test/metadata.yml new file mode 100644 index 000000000..6a345db63 --- /dev/null +++ b/examples/picosystem-hardware-test/metadata.yml @@ -0,0 +1,10 @@ +title: Hardware Test +description: A test of 32Blit's inputs and outputs. +author: pimoroni +splash: + file: hardware-test.png +icon: + file: hardware-test-icon.png +version: v1.0.0 +url: https://github.com/32blit/32blit-sdk +category: utility \ No newline at end of file From 9819d57bb59998568894ccb8b36f53d1d0256060 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 10 Sep 2021 12:51:15 +0100 Subject: [PATCH 8/9] pico: allow builds to use PWM audio with -DAUDIO_PWM Specify `-DAUDIO_PWM:bool=true` when configuring and builds will use AUDIO_PWM instead of AUDIO_BEEP. This is intended for PicoSystems which have been end-user modified with a 20x15mm .7w 8Ohm speaker. --- 32blit-pico/CMakeLists.txt | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/32blit-pico/CMakeLists.txt b/32blit-pico/CMakeLists.txt index f331bca21..6006c886e 100644 --- a/32blit-pico/CMakeLists.txt +++ b/32blit-pico/CMakeLists.txt @@ -7,7 +7,6 @@ set(32BLIT_PICO 1 PARENT_SCOPE) add_library(BlitHalPico INTERFACE) target_sources(BlitHalPico INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ff.c ${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ffunicode.c @@ -46,14 +45,25 @@ if(${PICO_BOARD} STREQUAL "vgaboard") elseif(${PICO_BOARD} STREQUAL "pimoroni_picosystem") message("Using picosystem...") target_compile_definitions(BlitHalPico INTERFACE - AUDIO_BEEP_PIN=11 - AUDIO_BEEP DISPLAY_ST7789 INPUT_GPIO ) + if(AUDIO_PWM) + target_link_libraries(BlitHalPico INTERFACE pico_audio_pwm) + target_compile_definitions(BlitHalPico INTERFACE + PICO_AUDIO_PWM_MONO_PIN=11 + PICO_AUDIO_PWM_PIO=1 + AUDIO_PWM + ) + else() + target_compile_definitions(BlitHalPico INTERFACE + AUDIO_BEEP_PIN=11 + AUDIO_BEEP + ) + endif() else() message(WARNING "Using default config for \"${PICO_BOARD}\"...") - target_link_libraries(BlitHalPico INTERFACE pico_audio_i2s) + target_link_libraries(BlitHalPico INTERFACE pico_audio_i2s) # messy explorer-based setup target_compile_definitions(BlitHalPico INTERFACE PICO_AUDIO_I2S_DATA_PIN=6 @@ -71,13 +81,13 @@ function(blit_executable_common NAME) endfunction() function(blit_executable_int_flash NAME SOURCES) - add_executable(${NAME} ${SOURCES} ${ARGN}) - target_link_libraries(${NAME} BlitHalPico BlitEngine) + add_executable(${NAME} ${SOURCES} ${ARGN}) + target_link_libraries(${NAME} BlitHalPico BlitEngine) - pico_enable_stdio_uart(${NAME} 1) - pico_enable_stdio_usb(${NAME} 0) + pico_enable_stdio_uart(${NAME} 1) + pico_enable_stdio_usb(${NAME} 0) - pico_add_extra_outputs(${NAME}) + pico_add_extra_outputs(${NAME}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.uf2 DESTINATION bin From a3377502055f4167d7285719ad05f6111ca70829 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 10 Sep 2021 13:49:33 +0100 Subject: [PATCH 9/9] pico: CMakeLists replace tabs with spaces --- 32blit-pico/CMakeLists.txt | 140 ++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/32blit-pico/CMakeLists.txt b/32blit-pico/CMakeLists.txt index 6006c886e..a1c68ea67 100644 --- a/32blit-pico/CMakeLists.txt +++ b/32blit-pico/CMakeLists.txt @@ -7,107 +7,107 @@ set(32BLIT_PICO 1 PARENT_SCOPE) add_library(BlitHalPico INTERFACE) target_sources(BlitHalPico INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ff.c - ${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ffunicode.c - - ${CMAKE_CURRENT_LIST_DIR}/audio.cpp - ${CMAKE_CURRENT_LIST_DIR}/file.cpp - ${CMAKE_CURRENT_LIST_DIR}/input.cpp - ${CMAKE_CURRENT_LIST_DIR}/led.cpp - ${CMAKE_CURRENT_LIST_DIR}/main.cpp - ${CMAKE_CURRENT_LIST_DIR}/storage.cpp - ${CMAKE_CURRENT_LIST_DIR}/st7789.cpp - ${CMAKE_CURRENT_LIST_DIR}/usb.cpp - ${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c + ${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ff.c + ${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ffunicode.c + + ${CMAKE_CURRENT_LIST_DIR}/audio.cpp + ${CMAKE_CURRENT_LIST_DIR}/file.cpp + ${CMAKE_CURRENT_LIST_DIR}/input.cpp + ${CMAKE_CURRENT_LIST_DIR}/led.cpp + ${CMAKE_CURRENT_LIST_DIR}/main.cpp + ${CMAKE_CURRENT_LIST_DIR}/storage.cpp + ${CMAKE_CURRENT_LIST_DIR}/st7789.cpp + ${CMAKE_CURRENT_LIST_DIR}/usb.cpp + ${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c ) pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/st7789.pio) target_link_libraries(BlitHalPico INTERFACE hardware_dma hardware_pio hardware_pwm hardware_spi pico_stdlib pico_unique_id tinyusb_device) target_include_directories(BlitHalPico INTERFACE - ${CMAKE_CURRENT_LIST_DIR} # for tusb_config - ${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs + ${CMAKE_CURRENT_LIST_DIR} # for tusb_config + ${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs ) target_compile_definitions(BlitHalPico INTERFACE - PICO_AUDIO_I2S_MONO_INPUT=1 - PICO_AUDIO_DMA_IRQ=1 + PICO_AUDIO_I2S_MONO_INPUT=1 + PICO_AUDIO_DMA_IRQ=1 ) if(${PICO_BOARD} STREQUAL "vgaboard") - message("Using VGA board...") - target_link_libraries(BlitHalPico INTERFACE pico_scanvideo_dpi pico_audio_i2s) - target_compile_definitions(BlitHalPico INTERFACE - PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA=1 - AUDIO_I2S - DISPLAY_SCANVIDEO - ) + message("Using VGA board...") + target_link_libraries(BlitHalPico INTERFACE pico_scanvideo_dpi pico_audio_i2s) + target_compile_definitions(BlitHalPico INTERFACE + PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA=1 + AUDIO_I2S + DISPLAY_SCANVIDEO + ) elseif(${PICO_BOARD} STREQUAL "pimoroni_picosystem") - message("Using picosystem...") - target_compile_definitions(BlitHalPico INTERFACE - DISPLAY_ST7789 - INPUT_GPIO - ) - if(AUDIO_PWM) - target_link_libraries(BlitHalPico INTERFACE pico_audio_pwm) - target_compile_definitions(BlitHalPico INTERFACE - PICO_AUDIO_PWM_MONO_PIN=11 - PICO_AUDIO_PWM_PIO=1 - AUDIO_PWM - ) - else() - target_compile_definitions(BlitHalPico INTERFACE - AUDIO_BEEP_PIN=11 - AUDIO_BEEP - ) - endif() + message("Using picosystem...") + target_compile_definitions(BlitHalPico INTERFACE + DISPLAY_ST7789 + INPUT_GPIO + ) + if(AUDIO_PWM) + target_link_libraries(BlitHalPico INTERFACE pico_audio_pwm) + target_compile_definitions(BlitHalPico INTERFACE + PICO_AUDIO_PWM_MONO_PIN=11 + PICO_AUDIO_PWM_PIO=1 + AUDIO_PWM + ) + else() + target_compile_definitions(BlitHalPico INTERFACE + AUDIO_BEEP_PIN=11 + AUDIO_BEEP + ) + endif() else() - message(WARNING "Using default config for \"${PICO_BOARD}\"...") - target_link_libraries(BlitHalPico INTERFACE pico_audio_i2s) - # messy explorer-based setup - target_compile_definitions(BlitHalPico INTERFACE - PICO_AUDIO_I2S_DATA_PIN=6 - PICO_AUDIO_I2S_CLOCK_PIN_BASE=20 - AUDIO_I2S - DISPLAY_ST7789 - INPUT_GPIO - ) + message(WARNING "Using default config for \"${PICO_BOARD}\"...") + target_link_libraries(BlitHalPico INTERFACE pico_audio_i2s) + # messy explorer-based setup + target_compile_definitions(BlitHalPico INTERFACE + PICO_AUDIO_I2S_DATA_PIN=6 + PICO_AUDIO_I2S_CLOCK_PIN_BASE=20 + AUDIO_I2S + DISPLAY_ST7789 + INPUT_GPIO + ) endif() function(blit_executable_common NAME) - target_link_libraries(${NAME} BlitEngine) + target_link_libraries(${NAME} BlitEngine) endfunction() function(blit_executable_int_flash NAME SOURCES) - add_executable(${NAME} ${SOURCES} ${ARGN}) - target_link_libraries(${NAME} BlitHalPico BlitEngine) + add_executable(${NAME} ${SOURCES} ${ARGN}) + target_link_libraries(${NAME} BlitHalPico BlitEngine) - pico_enable_stdio_uart(${NAME} 1) - pico_enable_stdio_usb(${NAME} 0) + pico_enable_stdio_uart(${NAME} 1) + pico_enable_stdio_usb(${NAME} 0) - pico_add_extra_outputs(${NAME}) + pico_add_extra_outputs(${NAME}) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.uf2 - DESTINATION bin - ) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.uf2 + DESTINATION bin + ) endfunction() function(blit_executable NAME SOURCES) - blit_executable_int_flash(${NAME} ${SOURCES} ${ARGN}) + blit_executable_int_flash(${NAME} ${SOURCES} ${ARGN}) endfunction() function(blit_metadata TARGET FILE) - # cause cmake to reconfigure whenever the asset list changes - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${FILE}) + # cause cmake to reconfigure whenever the asset list changes + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${FILE}) - # get the inputs/outputs for the asset tool (at configure time) - execute_process(COMMAND ${PYTHON_EXECUTABLE} -m ttblit cmake --config ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} --cmake ${CMAKE_CURRENT_BINARY_DIR}/metadata.cmake) - include(${CMAKE_CURRENT_BINARY_DIR}/metadata.cmake) + # get the inputs/outputs for the asset tool (at configure time) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -m ttblit cmake --config ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} --cmake ${CMAKE_CURRENT_BINARY_DIR}/metadata.cmake) + include(${CMAKE_CURRENT_BINARY_DIR}/metadata.cmake) - pico_set_program_name(${TARGET} "${METADATA_TITLE}") - pico_set_program_description(${TARGET} "${METADATA_DESCRIPTION}") - pico_set_program_version(${TARGET} "${METADATA_VERSION}") - pico_set_program_url(${TARGET} "${METADATA_URL}") + pico_set_program_name(${TARGET} "${METADATA_TITLE}") + pico_set_program_description(${TARGET} "${METADATA_DESCRIPTION}") + pico_set_program_version(${TARGET} "${METADATA_VERSION}") + pico_set_program_url(${TARGET} "${METADATA_URL}") endfunction()