From 207126b3b1bd4ad1f1ddc7bcc1dc4a839c2c5fba Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Wed, 23 Sep 2026 09:13:24 -0700 Subject: [PATCH 01/12] add devkit source files, and new DigitalControl (Switch debouncing for non-GPIO objects), included in daisy.h --- src/daisy.h | 1 + src/desktop_devkit.cpp | 144 ++++++++++++++++++++++++++++++++++++++ src/desktop_devkit.h | 73 +++++++++++++++++++ src/eurorack_devkit.cpp | 100 ++++++++++++++++++++++++++ src/eurorack_devkit.h | 58 +++++++++++++++ src/hid/digital_control.h | 50 +++++++++++++ src/pedal_devkit.cpp | 87 +++++++++++++++++++++++ src/pedal_devkit.h | 62 ++++++++++++++++ 8 files changed, 575 insertions(+) create mode 100644 src/desktop_devkit.cpp create mode 100644 src/desktop_devkit.h create mode 100644 src/eurorack_devkit.cpp create mode 100644 src/eurorack_devkit.h create mode 100644 src/hid/digital_control.h create mode 100644 src/pedal_devkit.cpp create mode 100644 src/pedal_devkit.h diff --git a/src/daisy.h b/src/daisy.h index 599648053..934c58bdc 100644 --- a/src/daisy.h +++ b/src/daisy.h @@ -26,6 +26,7 @@ #include "hid/switch.h" #include "hid/switch3.h" #include "hid/ctrl.h" +#include "hid/digital_control.h" #include "hid/gatein.h" #include "hid/parameter.h" #include "hid/usb.h" diff --git a/src/desktop_devkit.cpp b/src/desktop_devkit.cpp new file mode 100644 index 000000000..17dd4c8c2 --- /dev/null +++ b/src/desktop_devkit.cpp @@ -0,0 +1,144 @@ +#include "desktop_devkit.h" + +namespace daisy::desktop_devkit +{ +static constexpr I2CHandle::Config led_i2c_config + = {I2CHandle::Config::Peripheral::I2C_1, + {seed::D11, seed::D12}, + I2CHandle::Config::Speed::I2C_1MHZ}; + +static Hardware::LedDriver::DmaBuffer DMA_BUFFER_MEM_SECTION led_dma_buffer_a, + led_dma_buffer_b; + +void Hardware::Init() +{ + // Initialize stuff + seed.Init(true); + + /** Switches */ + tog_sw17.Init(daisy::seed::D19); + tog_sw18.Init(daisy::seed::D28, daisy::seed::D27); + + sd_detect.Init(daisy::seed::D7); + left_detect.Init(daisy::seed::D16); + right_detect.Init(daisy::seed::D17); + + ButtonSr::Config sr_cfg; + sr_cfg.clk = daisy::seed::D8; + sr_cfg.latch = daisy::seed::D9; + sr_cfg.data[0] = daisy::seed::D10; + button_sr.Init(sr_cfg); + for(auto &b : button) + b.Init(true); + + /** UART MIDI I/O */ + daisy::MidiUartHandler::Config midi_config; + midi_config.transport_config.periph + = daisy::UartHandler::Config::Peripheral::USART_1; + midi_config.transport_config.rx = daisy::seed::D14; + midi_config.transport_config.tx = daisy::seed::D13; + midi.Init(midi_config); + + /** ADC Inputs */ + daisy::AdcChannelConfig adc_cfg[3]; + auto conversion_speed + = daisy::AdcChannelConfig::ConversionSpeed::SPEED_810CYCLES_5; + adc_cfg[0].InitMux(daisy::seed::D15, + 8, + daisy::seed::D24, + daisy::seed::D25, + daisy::seed::D26, + conversion_speed); + adc_cfg[1].InitSingle(daisy::seed::D20, conversion_speed); + adc_cfg[2].InitSingle(daisy::seed::D21, conversion_speed); + seed.adc.Init(adc_cfg, 3); + + for(int i = 0; i < 8; i++) + pot[i].Init(seed.adc.GetMuxPtr(0, i), 1000.f); + for(int i = 0; i < 2; i++) + cv[i].InitBipolarCv(seed.adc.GetPtr(i + 1), 1000.f); + + /** Leds */ + daisy::I2CHandle i2c; + i2c.Init(led_i2c_config); + led_driver.Init(i2c, {0x00}, led_dma_buffer_a, led_dma_buffer_b); + ClearLeds(); + UpdateLeds(); + + /** Gate Ins */ + gate_in[0].Init(daisy::seed::D0); + gate_in[1].Init(daisy::seed::D18); + + /** DAC/Gate Output */ + daisy::DacHandle::Config dac_cfg; + dac_cfg.bitdepth = daisy::DacHandle::BitDepth::BITS_12; + dac_cfg.buff_state = daisy::DacHandle::BufferState::ENABLED; + dac_cfg.chn = daisy::DacHandle::Channel::BOTH; + dac_cfg.mode = daisy::DacHandle::Mode::POLLING; + seed.dac.Init(dac_cfg); + // Alternatively: DMA mode + // dac_cfg.mode = daisy::DacHandle::Mode::DMA; + // dac_cfg.target_samplerate = 12000; + + seed.adc.Start(); +} + +void Hardware::UpdateAllControls() +{ + button_sr.Update(); + for(int i = 0; i < 16; i++) + { + int sr_idx = 15 - i; + button[i].Debounce(button_sr.State(sr_idx)); + }; + for(auto &p : pot) + p.Process(); + for(auto &c : cv) + c.Process(); + tog_sw17.Debounce(); +} + +void Hardware::SetDacOut(DacHandle::Channel channel, uint16_t code) +{ + seed.dac.WriteValue(channel, code); +} + +void Hardware::ClearLeds() +{ + led_driver.SetAllTo(1.f); +} + +void Hardware::UpdateLeds() +{ + led_driver.SwapBuffersAndTransmit(); +} + +void Hardware::SetLed(int idx, float brightness) +{ + led_driver.SetLed(idx, 1.f - brightness); +} + +void Hardware::StartLowPriorityCallback(TimerHandle::PeriodElapsedCallback cb, + uint32_t target_freq, + void * data) +{ + TimerHandle::Config timcfg; + timcfg.periph = daisy::TimerHandle::Config::Peripheral::TIM_5; + timcfg.dir = daisy::TimerHandle::Config::CounterDir::UP; + auto tim_base_freq = daisy::System::GetPClk2Freq(); + auto tim_target_freq = target_freq; + auto tim_period = tim_base_freq / tim_target_freq; + timcfg.period = tim_period; + timcfg.enable_irq = true; + tim5_handle.Init(timcfg); + tim5_handle.SetCallback(cb, data); + tim5_handle.Start(); +} + +/** Stops an ongoing low-priority callback */ +void Hardware::StopLowPriorityCallback() +{ + tim5_handle.Stop(); +} + +} // namespace daisy::desktop_devkit \ No newline at end of file diff --git a/src/desktop_devkit.h b/src/desktop_devkit.h new file mode 100644 index 000000000..3c6ec8791 --- /dev/null +++ b/src/desktop_devkit.h @@ -0,0 +1,73 @@ +#pragma once +#include "daisy_seed.h" + +namespace daisy::desktop_devkit +{ +class Hardware +{ + public: + Hardware() {} + + using LedDriver = LedDriverPca9685<1, true>; + using ButtonSr = ShiftRegister4021<2, 1>; + + DaisySeed seed; + Switch tog_sw17; + Switch3 tog_sw18; + ButtonSr button_sr; + GateIn gate_in[2]; + AnalogControl pot[8], cv[2]; + DigitalControl button[16]; + MidiUartHandler midi; + LedDriver led_driver; + TimerHandle tim5_handle; + // Plug Detection + Switch sd_detect, left_detect, right_detect; + + /** Initialize the hardware */ + void Init(); + + /** Process all analog inputs, debounce digital inputs, and update their + * internally stored states. + */ + void UpdateAllControls(); + + /** Write the code to the DAC output + * @param channel DAC channel to write to + * @param code the 0-4096 code to write corresponding to the output voltage + */ + void SetDacOut(DacHandle::Channel channel, uint16_t code); + + /** Reset all LEDs to their off state */ + void ClearLeds(); + + /** Flush the current LED values to the hardware. + * Changes to the LED brightnesses will only take effect + * when this method is called. + */ + void UpdateLeds(); + + /** Set the brightness for a specific LED + * @param idx index of the LED from 0-15 corresponding to D1 to D16 + * @param brightness brightness level from 0-1 + */ + void SetLed(int idx, float brightness); + + /** This starts a recurring callback at a specified interval. The callback is + * run on the lowest priority interrupt level. This provides a hook for + * non-background tasks that should interrupt low level activity like disk + * i/o, etc. + * + * @param cb callback function to take place at the specified frequency + * @param target_freq target frequency in hertz for the callback to run + * @param data optional pointer to context data accessible from the callback + */ + void StartLowPriorityCallback(TimerHandle::PeriodElapsedCallback cb, + uint32_t target_freq, + void * data = nullptr); + + /** Stops an ongoing low-priority callback */ + void StopLowPriorityCallback(); +}; + +} // namespace daisy::desktop_devkit \ No newline at end of file diff --git a/src/eurorack_devkit.cpp b/src/eurorack_devkit.cpp new file mode 100644 index 000000000..77deea13c --- /dev/null +++ b/src/eurorack_devkit.cpp @@ -0,0 +1,100 @@ +#include "eurorack_devkit.h" + +namespace daisy::eurorack_devkit { + +void Hardware::Init() { + seed.Init(true); + sw1.Init(seed::D0); + sw2.Init(seed::D20); + sw3.Init(seed::D7, seed::D27); //< wired opposite from expected.. + sw4.Init(seed::D12); + + AdcChannelConfig adc_config[5]; + auto conversion_speed = AdcChannelConfig::ConversionSpeed::SPEED_810CYCLES_5; + adc_config[0].InitMux(seed::D15, 8, seed::D24, seed::D25, seed::D26, + conversion_speed); + adc_config[1].InitSingle(seed::D18, conversion_speed); + adc_config[2].InitSingle(seed::D17, conversion_speed); + adc_config[3].InitSingle(seed::D16, conversion_speed); + adc_config[4].InitSingle(seed::D19, conversion_speed); + seed.adc.Init(adc_config, 5); + for (size_t i = 0; i < kNumPots; i++) { + pot[i].Init(seed.adc.GetMuxPtr(0, i), 1000.f); + } + for (size_t i = 0; i < kNumCVs; i++) { + cv[i].InitBipolarCv(seed.adc.GetPtr(i + 1), 1000.f); + } + + led1.Init(seed::D9, seed::D28, seed::D8, false); + led2.Init(seed::D11, false); + + gate_in1.Init(seed::D10); + gate_in2.Init(seed::D21); + + // DAC init + // Maybe this becomes separate and/or optional to make it + // easier to set up these outputs as GPIO if the user wants? + DacHandle::Config dac_config; + dac_config.bitdepth = DacHandle::BitDepth::BITS_12; + dac_config.buff_state = DacHandle::BufferState::DISABLED; + dac_config.mode = DacHandle::Mode::POLLING; + dac_config.chn = DacHandle::Channel::BOTH; + seed.dac.Init(dac_config); + + MidiUartHandler::Config midi_config; + midi_config.transport_config.periph = + UartHandler::Config::Peripheral::USART_1; + midi_config.transport_config.rx = seed::D14; + midi_config.transport_config.tx = seed::D13; + midi.Init(midi_config); + + seed.adc.Start(); +} + +void Hardware::UpdateAllControls() { + for (auto &p : pot) + p.Process(); + for (auto &c : cv) + c.Process(); + sw1.Debounce(); + sw2.Debounce(); + sw4.Debounce(); +} + +void Hardware::SetDacOut(DacHandle::Channel channel, uint16_t code) { + seed.dac.WriteValue(channel, code); +} + +void Hardware::PrintAllControls() { + // TODO: consider updating this to write everything to one buffer, and then + // transmit to avoid the screen flicker of everything writing in separate + // transactions. + using Log = Logger; + const char *sw3_str = sw3.Read() == Switch3::POS_LEFT + ? "L" + : sw3.Read() == Switch3::POS_RIGHT ? "R" : "C"; + + Log::PrintLine("\033[2J\033[H"); //< Clear the terminal + Log::PrintLine("Pedal DevKit Controls:"); + Log::PrintLine("----Switches----"); + Log::PrintLine("\tSW1: %s\tSW2: %s\tSW3: %s", sw1.Pressed() ? "X" : "O", + sw2.Pressed() ? "X" : "O", sw3_str, sw4.Pressed() ? "R" : "L"); + Log::PrintLine("----Gate Ins----"); + Log::PrintLine("\tGate In 1: %s\tGate In 2: %s", gate_in1.State() ? "X" : "O", + gate_in2.State() ? "X" : "O"); + Log::PrintLine("------ADCs------"); + Log::PrintLine("\tVR1: " FLT_FMT3 "\tVR2: " FLT_FMT3 "\tVR3: " FLT_FMT3 + "\tVR4: " FLT_FMT3, + FLT_VAR3(pot[0].Value()), FLT_VAR3(pot[1].Value()), + FLT_VAR3(pot[2].Value()), FLT_VAR3(pot[3].Value())); + Log::PrintLine("\tVR5: " FLT_FMT3 "\tVR6: " FLT_FMT3 "\tVR7: " FLT_FMT3 + "\tVR8: " FLT_FMT3, + FLT_VAR3(pot[4].Value()), FLT_VAR3(pot[5].Value()), + FLT_VAR3(pot[6].Value()), FLT_VAR3(pot[7].Value())); + Log::PrintLine("\tCV 1: " FLT_FMT3 "\tCV 2: " FLT_FMT3 "\tCV 3: " FLT_FMT3 + "\tCV 4: " FLT_FMT3, + FLT_VAR3(cv[0].Value()), FLT_VAR3(cv[1].Value()), + FLT_VAR3(cv[2].Value()), FLT_VAR3(cv[3].Value())); +} + +} // namespace daisy::eurorack_devkit \ No newline at end of file diff --git a/src/eurorack_devkit.h b/src/eurorack_devkit.h new file mode 100644 index 000000000..1bf00f34f --- /dev/null +++ b/src/eurorack_devkit.h @@ -0,0 +1,58 @@ +#pragma once + +#include "daisy_seed.h" + +namespace daisy::eurorack_devkit { + +class Hardware { +public: + Hardware() {} + + /** Number of Pots on the DevKit */ + inline static constexpr size_t kNumPots = 8; + /** Number of CV inputs on the DevKit */ + inline static constexpr size_t kNumCVs = 4; + + // SOM + DaisySeed seed; + // Tactile Switches + Switch sw1, sw2; + // Toggle Switches + Switch3 sw3; + Switch sw4; + // Pots + AnalogControl pot[kNumPots]; + // Bipolar CV Inputs + AnalogControl cv[kNumCVs]; + // Gate Inputs + GateIn gate_in1, gate_in2; + // MIDI + MidiUartHandler midi; + + // LEDs + RgbLed led1; + Led led2; + + /** Initialize the hardware */ + void Init(); + + /** Process all analog inputs, debounce digital inputs, and update their + * internally stored states. + */ + void UpdateAllControls(); + + /** Write the code to the DAC output + * @param channel DAC channel to write to + * @param code the 0-4096 code to write corresponding to the output voltage + */ + void SetDacOut(DacHandle::Channel channel, uint16_t code); + + /** Print the state of all hardware inputs in a human readable block over + * serial using the Seed's built-in USB port. + * + * Start the Seed's logger with `seed.StartLog()` prior to using this method. + */ + void PrintAllControls(); +}; + +} // namespace daisy::eurorack_devkit diff --git a/src/hid/digital_control.h b/src/hid/digital_control.h new file mode 100644 index 000000000..a443bee1e --- /dev/null +++ b/src/hid/digital_control.h @@ -0,0 +1,50 @@ +#pragma once +#include "daisy.h" + +/** Debouncer for non-GPIO switch inputs independent of their source. + * For getting `Switch` like behavior from inputs connected to shiftregisters, + * etc. + * + * Maintains the state and allows checks for transitions, timing, etc. + * + * Unlike `AnalogControl`, this does not take a pointer to an externally + * updated value. This is because the input to this may often be a callable + * (e.g. shiftreg.State(x), gpio.Read()) that may not be stateful. + */ +struct DigitalControl +{ + uint8_t state_; + bool flip_; + uint32_t rising_edge_time_; + + DigitalControl() {} + + inline void Init(bool flip) + { + flip_ = flip; + state_ = 0x00; + } + + inline void Debounce(bool input) + { + uint8_t in_val; + if(flip_) + in_val = input ? 0 : 1; + else + in_val = input ? 1 : 0; + state_ = (state_ << 1) | in_val; + if(RisingEdge()) + { + rising_edge_time_ = daisy::System::GetNow(); + } + } + + inline bool RisingEdge() const { return state_ == 0x7f; } + inline bool FallingEdge() const { return state_ == 0x80; } + inline bool Pressed() const { return state_ == 0xff; } + + inline uint32_t TimeHeldMs() const + { + return Pressed() ? daisy::System::GetNow() - rising_edge_time_ : 0; + } +}; \ No newline at end of file diff --git a/src/pedal_devkit.cpp b/src/pedal_devkit.cpp new file mode 100644 index 000000000..e24599da2 --- /dev/null +++ b/src/pedal_devkit.cpp @@ -0,0 +1,87 @@ +#include "pedal_devkit.h" + +namespace daisy::pedal_devkit { + +void Hardware::Init() { + seed.Init(true); + sw1.Init(seed::D7, seed::D8); //< wired opposite from expected.. + sw2.Init(seed::D9); + sw3.Init(seed::D22); + sw4.Init(seed::D0); + sw5.Init(seed::D28); + fsw_1.Init(seed::D10); + fsw_2.Init(seed::D23); + sd_detect.Init(seed::D11); + + AdcChannelConfig adc_cfg[kNumPots + 1]; + auto conversion_speed = AdcChannelConfig::ConversionSpeed::SPEED_810CYCLES_5; + // Pots + adc_cfg[0].InitSingle(seed::D15, conversion_speed); + adc_cfg[1].InitSingle(seed::D16, conversion_speed); + adc_cfg[2].InitSingle(seed::D17, conversion_speed); + adc_cfg[3].InitSingle(seed::D18, conversion_speed); + adc_cfg[4].InitSingle(seed::D19, conversion_speed); + adc_cfg[5].InitSingle(seed::D20, conversion_speed); + // Expression + adc_cfg[6].InitSingle(seed::D21, conversion_speed); + seed.adc.Init(adc_cfg, kNumPots + 1); + + for (size_t i = 0; i < kNumPots; i++) + pot[i].Init(seed.adc.GetPtr(i), 1000.f); + expression.Init(seed.adc.GetPtr(kNumPots), 1000.f); + + led1.Init(seed::D24, false); + led2.Init(seed::D25, seed::D27, seed::D26, false); + + MidiUartHandler::Config midi_config; + midi_config.transport_config.periph = + UartHandler::Config::Peripheral::USART_1; + midi_config.transport_config.rx = seed::D14; + midi_config.transport_config.tx = seed::D13; + midi.Init(midi_config); + + seed.adc.Start(); +} + +void Hardware::UpdateAllControls() { + for (auto &p : pot) + p.Process(); + expression.Process(); + + sw2.Debounce(); + sw3.Debounce(); + sw4.Debounce(); + sw5.Debounce(); + fsw_1.Debounce(); + fsw_2.Debounce(); + sd_detect.Debounce(); +} + +void Hardware::PrintAllControls() { + using Log = Logger; + const char *sw1_str = sw1.Read() == Switch3::POS_LEFT + ? "L" + : sw1.Read() == Switch3::POS_RIGHT ? "R" : "C"; + + Log::PrintLine("\033[2J\033[H]"); //< Clear the terminal + Log::PrintLine("Pedal DevKit Controls:"); + Log::PrintLine("----Switches----"); + Log::PrintLine("\tSW1: %s\tSW2: %s\tSW3: %s", sw1_str, + sw2.Pressed() ? "R" : "L", sw3.Pressed() ? "R" : "L"); + Log::PrintLine("\tSW4: %s\tSW5: %s", sw4.Pressed() ? "X" : "O", + sw5.Pressed() ? "X" : "O"); + Log::PrintLine("\tFSW1: %s\tFSW2: %s", fsw_1.Pressed() ? "X" : "O", + fsw_2.Pressed() ? "X" : "O"); + Log::PrintLine("\tSD Detect: %s", + sd_detect.Pressed() ? "SD Card Detected" : "No SD Card"); + Log::PrintLine("------ADCs------"); + Log::PrintLine("\tVR1: " FLT_FMT3 "\tVR2: " FLT_FMT3 "\tVR3: " FLT_FMT3, + FLT_VAR3(pot[0].Value()), FLT_VAR3(pot[1].Value()), + FLT_VAR3(pot[2].Value())); + Log::PrintLine("\tVR4: " FLT_FMT3 "\tVR5: " FLT_FMT3 "\tVR6: " FLT_FMT3, + FLT_VAR3(pot[3].Value()), FLT_VAR3(pot[4].Value()), + FLT_VAR3(pot[5].Value())); + Log::PrintLine("\tExpression: " FLT_FMT3, FLT_VAR3(expression.Value())); +} + +} // namespace daisy::pedal_devkit \ No newline at end of file diff --git a/src/pedal_devkit.h b/src/pedal_devkit.h new file mode 100644 index 000000000..18d4438f6 --- /dev/null +++ b/src/pedal_devkit.h @@ -0,0 +1,62 @@ +#pragma once + +#include "daisy_seed.h" + +namespace daisy::pedal_devkit +{ +/** Board support for the Pedal DevKit + * + * Provides access to all HW on the DevKit with convenience methods for common + * behaviors like initialization, and updating values. + */ +class Hardware +{ + public: + Hardware() {} + + // SOM + DaisySeed seed; + + /** Number of Pots on the DevKit */ + inline static constexpr size_t kNumPots = 6; + + // Analog Inputs + /** Pot inputs. Labeled VR1 through VR6 on the PCB. */ + AnalogControl pot[kNumPots]; + AnalogControl expression; + + // Toggles + Switch3 sw1; + Switch sw2, sw3; + + // Tactile Switches + Switch sw4, sw5; + + // Footswitches + Switch fsw_1, fsw_2; + + // SD Card detection + Switch sd_detect; + + // LEDs + Led led1; + RgbLed led2; + + // 5-Pin DIN MIDI via UART + daisy::MidiUartHandler midi; + + /** Initialize all of the hardware, and start the ADC */ + void Init(); + + /** Process all analog inputs, debounce switch inputs, and update internally + * stored states */ + void UpdateAllControls(); + + /** Print the state of all hardware inputs in a human readable block over + * serial using the Seed's built-in USB port. + * + * Start the Seed's logger with `seed.StartLog()` prior to using this method. + */ + void PrintAllControls(); +}; +} // namespace daisy::pedal_devkit From 05b2d54c03052128225404c22ea331986c63b206 Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Wed, 23 Sep 2026 09:13:48 -0700 Subject: [PATCH 02/12] bump C++ Standard to gnu++17 (previously gnu++14) --- Makefile | 5 ++++- core/Makefile | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 03874ca1c..4e8b1b92e 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,9 @@ daisy_field \ daisy_versio \ daisy_legio \ daisy_patch_sm \ +desktop_devkit \ +eurorack_devkit \ +pedal_devkit \ sys/fatfs \ sys/system \ dev/sr_595 \ @@ -345,7 +348,7 @@ CPPFLAGS += \ -fno-rtti C_STANDARD = -std=gnu11 -CPP_STANDARD += -std=gnu++14 +CPP_STANDARD += -std=gnu++17 # default action: build all all: $(BUILD_DIR)/$(TARGET).a diff --git a/core/Makefile b/core/Makefile index d6619f8a6..d8d774425 100644 --- a/core/Makefile +++ b/core/Makefile @@ -202,7 +202,7 @@ CPPFLAGS += \ -Wno-register C_STANDARD = -std=gnu11 -CPP_STANDARD ?= -std=gnu++14 +CPP_STANDARD ?= -std=gnu++17 ####################################### From 88a5133034d8b378eb078336d052eeece08c9a2f Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Wed, 23 Sep 2026 09:15:28 -0700 Subject: [PATCH 03/12] resolve vs code intellisense issues with missing USBH middleware/conf --- .vscode/c_cpp_properties.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 23c66744c..127669ccd 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -8,12 +8,16 @@ "${workspaceRoot}/tests/googletest/googletest/include", "${workspaceRoot}/src/sys", "${workspaceRoot}/src/usbd", + "${workspaceRoot}/src/usbh", "${workspaceRoot}/Drivers/CMSIS_5/CMSIS/Core/Include", "${workspaceRoot}/Drivers/CMSIS-Device/ST/STM32H7xx/Include", "${workspaceRoot}/Drivers/STM32H7xx_HAL_Driver/Inc", "${workspaceRoot}/Drivers/STM32H7xx_HAL_Driver/Inc/Legacy", "${workspaceRoot}/Middlewares/ST/STM32_USB_Device_Library/Core/Inc", "${workspaceRoot}/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc", + "${workspaceRoot}/Middlewares/ST/STM32_USB_Host_Library/Core/Inc", + "${workspaceRoot}/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc", + "${workspaceRoot}/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc", "${workspaceRoot}/Middlewares/Third_Party/FatFs/src" ], "defines": [ From c22356094576a0bbee737c67b0bccb661d942157 Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Wed, 23 Sep 2026 09:17:59 -0700 Subject: [PATCH 04/12] added devkits and C++ standard bump to CMake build. --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 42f15065d..d7e54588c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,9 @@ add_library(daisy STATIC ${MODULE_DIR}/daisy_pod.cpp ${MODULE_DIR}/daisy_seed.cpp ${MODULE_DIR}/daisy_versio.cpp + ${MODULE_DIR}/desktop_devkit.cpp + ${MODULE_DIR}/eurorack_devkit.cpp + ${MODULE_DIR}/pedal_devkit.cpp ${MODULE_DIR}/dev/codec_ak4556.cpp ${MODULE_DIR}/dev/codec_pcm3060.cpp ${MODULE_DIR}/dev/codec_wm8731.cpp @@ -130,15 +133,13 @@ target_compile_options(daisy PRIVATE $<$:-Wno-missing-attributes> ) - set_target_properties(daisy PROPERTIES - CXX_STANDARD 14 + CXX_STANDARD 17 CXX_STANDARD_REQUIRED C_STANDARD 11 C_STANDARD_REQUIRED ) - # Don't add examples if we're being included in another project if(PROJECT_IS_TOP_LEVEL) add_subdirectory(examples EXCLUDE_FROM_ALL) From 834f935d873e241a2ce09caca57ed72a6b1aef96 Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Wed, 23 Sep 2026 11:14:15 -0700 Subject: [PATCH 05/12] basic template/example programs for the Eurorack and Pedal devkits. --- .../devkits/Eurorack-DevKit-Template/Makefile | 35 ++++++ .../Eurorack-DevKit-Template/src/main.cpp | 109 ++++++++++++++++++ .../devkits/Pedal-DevKit-Template/Makefile | 31 +++++ .../Pedal-DevKit-Template/src/main.cpp | 96 +++++++++++++++ 4 files changed, 271 insertions(+) create mode 100644 examples/devkits/Eurorack-DevKit-Template/Makefile create mode 100644 examples/devkits/Eurorack-DevKit-Template/src/main.cpp create mode 100644 examples/devkits/Pedal-DevKit-Template/Makefile create mode 100644 examples/devkits/Pedal-DevKit-Template/src/main.cpp diff --git a/examples/devkits/Eurorack-DevKit-Template/Makefile b/examples/devkits/Eurorack-DevKit-Template/Makefile new file mode 100644 index 000000000..6650d16c5 --- /dev/null +++ b/examples/devkits/Eurorack-DevKit-Template/Makefile @@ -0,0 +1,35 @@ +# Project Name +TARGET = Eurorack-DevKit-Template + +# Configure for debugging +# common configurations: +# use DEBUG = 1 and OPT = -Og for debugging +# or DEBUG = 0 and OPT = -O3 for performance +DEBUG = 1 +OPT = -Og + +# Use bootloader? +#APP_TYPE=BOOT_SRAM + +# Sources +CPP_SOURCES = src/main.cpp + +#CPP_STANDARD=-std=gnu++17 + +LIBDAISY_DIR = ../../../ + +# (optional) Add DaisySP +# DAISYSP_DIR = ../../DaisySP +# USE_DAISYSP_LGPL=1 + +# C_INCLUDES += -I../include/ -I./include/ + +# (optional) Includes FatFS source files within project. +USE_FATFS = 1 + +# Core location, and generic Makefile. +SYSTEM_FILES_DIR = $(LIBDAISY_DIR)/core + +BOOT_BIN=$(SYSTEM_FILES_DIR)/dsy_bootloader_v6_4-extdfu-2000ms.bin + +include $(SYSTEM_FILES_DIR)/Makefile diff --git a/examples/devkits/Eurorack-DevKit-Template/src/main.cpp b/examples/devkits/Eurorack-DevKit-Template/src/main.cpp new file mode 100644 index 000000000..83aac582a --- /dev/null +++ b/examples/devkits/Eurorack-DevKit-Template/src/main.cpp @@ -0,0 +1,109 @@ +/** Eurorack DevKit Template + * + * Basic template program for the Eurorack DevKit + * + * This program: + * - initializes the Eurorack DevKit hardware + * - starts an audio callback to do pass through and update the controls + * - blinks the LEDs + * - Writes a signal to the DAC outputs + * - Sends MIDI notes received on the MIDI input to the MIDI output + * - Prints all input state over USB serial + */ +#include "eurorack_devkit.h" + +using namespace daisy; +using namespace daisy::eurorack_devkit; + +Hardware hw; + +void AudioCallback(AudioHandle::InputBuffer in, + AudioHandle::OutputBuffer out, + size_t size) +{ + hw.UpdateAllControls(); + + for(size_t i = 0; i < size; i++) + { + out[0][i] = in[0][i]; + out[1][i] = in[1][i]; + } +} + +int main(void) +{ + hw.Init(); + System::Delay(50); + hw.seed.StartLog(false); + + hw.seed.StartAudio(AudioCallback); + + hw.midi.StartReceive(); + + auto last_print = System::GetNow(); + auto last_dac_write = System::GetNow(); + uint16_t dac_value = 0; + + while(true) + { + auto now = System::GetNow(); + // Blink the Seed's LED + hw.seed.SetLed((now & 511) < 255); + + // Blink each color of the RGB LED at different rates: + auto blink_red = (now & 511) < 255; + auto blink_green = (now & 1023) < 511; + auto blink_blue = (now & 2047) < 1023; + hw.led1.Set(blink_red, blink_green, blink_blue); + hw.led2.Set(blink_red); + hw.led1.Update(); + hw.led2.Update(); + + // Restart MIDI in the event of errors. + hw.midi.Listen(); + + // Handle MIDI events + while(hw.midi.HasEvents()) + { + auto msg = hw.midi.PopEvent(); + switch(msg.type) + { + case NoteOn: + // Echo note on messages to the MIDI out + { + uint8_t bytes[3] = {0x90, 0x00, 0x00}; + bytes[1] = msg.data[0]; + bytes[2] = msg.data[1]; + hw.midi.SendMessage(bytes, 3); + } + break; + default: break; + } + } + + /** Write a ramp (cv out 1) and saw (cv out 2) waveform to the DAC outputs + * Approx. 2.5s period for waveform (0.005s * (4096 / 8)) = 2.56s + */ + if(now - last_dac_write > 5) + { + dac_value += 8; + if(dac_value > 4095) + { + dac_value = 0; + } + hw.SetDacOut(DacHandle::Channel::ONE, dac_value); + hw.SetDacOut(DacHandle::Channel::TWO, 4095 - dac_value); + last_dac_write = now; + } + + if(now - last_print > 100) + { + hw.PrintAllControls(); + last_print = now; + } + + System::Delay(1); + } + + return 0; +} \ No newline at end of file diff --git a/examples/devkits/Pedal-DevKit-Template/Makefile b/examples/devkits/Pedal-DevKit-Template/Makefile new file mode 100644 index 000000000..a955bbea3 --- /dev/null +++ b/examples/devkits/Pedal-DevKit-Template/Makefile @@ -0,0 +1,31 @@ +# Project Name +TARGET = Pedal-DevKit-Template + +# Configure for debugging +# common configurations: +# use DEBUG = 1 and OPT = -Og for debugging +# or DEBUG = 0 and OPT = -O3 for performance +DEBUG = 1 +OPT = -Og + +#(optional) use the bootloader +# APP_TYPE=BOOT_SRAM + +# CPP_STANDARD= -std=gnu++17 + +# Sources +CPP_SOURCES = src/main.cpp + +LIBDAISY_DIR = ../../../ + +# (optional) Add DaisySP +# DAISYSP_DIR = ../path/to/DaisySP +# USE_DAISYSP_LGPL=1 + +# (optional) Includes FatFS source files within project. +USE_FATFS = 1 + +# Core location, and generic Makefile. +SYSTEM_FILES_DIR = $(LIBDAISY_DIR)/core + +include $(SYSTEM_FILES_DIR)/Makefile diff --git a/examples/devkits/Pedal-DevKit-Template/src/main.cpp b/examples/devkits/Pedal-DevKit-Template/src/main.cpp new file mode 100644 index 000000000..12be2967f --- /dev/null +++ b/examples/devkits/Pedal-DevKit-Template/src/main.cpp @@ -0,0 +1,96 @@ +/** Pedal DevKit Template + * + * Basic template program for the Pedal DevKit + * + * This program: + * - initializes the Pedal DevKit hardware + * - starts an audio callback to do pass through and update the controls + * - blinks the LEDs + * - Sends MIDI notes received on the MIDI input to the MIDI output + * - Prints all input states over USB serial + */ +#include "pedal_devkit.h" + +using namespace daisy; +using namespace daisy::pedal_devkit; + +using Log = Logger; + +Hardware hw; + +void AudioCallback(AudioHandle::InputBuffer in, + AudioHandle::OutputBuffer out, + size_t size) +{ + hw.UpdateAllControls(); + + for(size_t i = 0; i < size; i++) + { + out[0][i] = in[0][i]; + out[1][i] = in[1][i]; + } +} + +int main(void) +{ + hw.Init(); + System::Delay(50); + Log::StartLog(false); + + hw.seed.StartAudio(AudioCallback); + + hw.midi.StartReceive(); + + auto last_print = System::GetNow(); + + while(true) + { + // Record the current time. + auto now = System::GetNow(); + + // Blink the Seed's LED + hw.seed.SetLed((now & 511) < 255); + + // Blink each color of the RGB LED at different rates: + auto blink_red = (now & 511) < 255; + auto blink_green = (now & 1023) < 511; + auto blink_blue = (now & 2047) < 1023; + hw.led1.Set(blink_red); + hw.led2.Set(blink_red, blink_green, blink_blue); + hw.led1.Update(); + hw.led2.Update(); + + hw.midi.Listen(); // Restart MIDI in the event of errors. + + /** Handle MIDI events */ + while(hw.midi.HasEvents()) + { + auto msg = hw.midi.PopEvent(); + switch(msg.type) + { + case NoteOn: + // Echo note on messages to the MIDI out + { + uint8_t bytes[3] = {0x90, 0x00, 0x00}; + bytes[1] = msg.data[0]; + bytes[2] = msg.data[1]; + hw.midi.SendMessage(bytes, 3); + } + break; + default: break; + } + } + + // Print Everything + if(now - last_print > 50) + { + hw.PrintAllControls(); + last_print = now; + } + + // If we start doing more things, we can remove the delay + System::Delay(1); + } + + return 0; +} \ No newline at end of file From 75c6f97c5f98e3ee130667d399113bfd4c8346c6 Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Wed, 23 Sep 2026 16:04:46 -0700 Subject: [PATCH 06/12] Desktop DevKit UI Template example, and minor tweaks to desktop devkit Hardware class. --- .../Desktop-DevKit-UI-Template/Makefile | 33 +++ .../Desktop-DevKit-UI-Template/README.md | 38 +++ .../Desktop-DevKit-UI-Template/src/main.cpp | 230 ++++++++++++++++++ .../src/main_page.h | 56 +++++ .../Desktop-DevKit-UI-Template/src/ui_glue.h | 34 +++ .../src/userinterface.h | 98 ++++++++ src/desktop_devkit.cpp | 16 +- 7 files changed, 503 insertions(+), 2 deletions(-) create mode 100644 examples/devkits/Desktop-DevKit-UI-Template/Makefile create mode 100644 examples/devkits/Desktop-DevKit-UI-Template/README.md create mode 100644 examples/devkits/Desktop-DevKit-UI-Template/src/main.cpp create mode 100644 examples/devkits/Desktop-DevKit-UI-Template/src/main_page.h create mode 100644 examples/devkits/Desktop-DevKit-UI-Template/src/ui_glue.h create mode 100644 examples/devkits/Desktop-DevKit-UI-Template/src/userinterface.h diff --git a/examples/devkits/Desktop-DevKit-UI-Template/Makefile b/examples/devkits/Desktop-DevKit-UI-Template/Makefile new file mode 100644 index 000000000..9a7acddfd --- /dev/null +++ b/examples/devkits/Desktop-DevKit-UI-Template/Makefile @@ -0,0 +1,33 @@ +# Project Name +TARGET = Desktop-DevKit-UI-Template + +# Configure for debugging +# common configurations: +# use DEBUG = 1 and OPT = -Og for debugging +# or DEBUG = 0 and OPT = -O3 for performance +DEBUG = 1 +OPT = -Og + +# (optional) use bootloader +APP_TYPE=BOOT_SRAM + +# Sources +CPP_SOURCES = src/main.cpp + +#C_INCLUDES += -I./include/ + +LIBDAISY_DIR = ../../../ + +# (optional) Add DaisySP +# DAISYSP_DIR = ../path/to/DaisySP +# USE_DAISYSP_LGPL=1 + +# (optional) Includes FatFS source files within project. +USE_FATFS = 1 + +# Core location, and generic Makefile. +SYSTEM_FILES_DIR = $(LIBDAISY_DIR)/core + +BOOT_BIN=$(SYSTEM_FILES_DIR)/dsy_bootloader_v6_4-extdfu-2000ms.bin + +include $(SYSTEM_FILES_DIR)/Makefile diff --git a/examples/devkits/Desktop-DevKit-UI-Template/README.md b/examples/devkits/Desktop-DevKit-UI-Template/README.md new file mode 100644 index 000000000..8e4b0616f --- /dev/null +++ b/examples/devkits/Desktop-DevKit-UI-Template/README.md @@ -0,0 +1,38 @@ +# Desktop Devkit UI Template + +This example is a bit more complex than the other examples in the repo. + +All inputs for the Desktop DevKit are read, and printed when changed to Serial over the external USB port, also used to power the DevKit. + +The 16 buttons, 8 pots, and LEDs are all managed using libDaisy's UI class from `main_page.h`. + +As usual inputs are read in the AudioCallback. UI Events are then created for the relevant pieces of the interface. +Inside the Low-priority Callback, the events are handled, and the LED UI is redrawn. +The Low-priority Callback is used so that things like SD Card Disk I/O, QSPI saving, etc. that may block the main while() loop do not cause the UI to become unresponsive, or appear stuck. + +## Flashing to the Daisy + +This is designed to use the external USB version of the bootloader. + +This version of the bootloader can be flashed to the daisy via the built-in USB port by running `make program-boot` from this directory, or by selecting the "v6.x (external)" variant from the [web programmer](https://flash.daisy.audio/). + +Once the bootloader has been flashed to the Daisy, you can power connect the USB-C cable from your computer to the Desktop Devkit's USB-C port (located above the Seed3). + +With the device connected, press RESET and then BOOT on the Seed. +You should see the USR LED on the Daisy blink quickly and then start slowly pulsing. + +While in this state you can run: `make program-dfu`, or upload the `Desktop-DevKit-UI-Template.bin` file to the [web programmer](https://flash.daisy.audio/) to program the example to the Seed. + +Once bootloader is programmed onto the Seed it does not need to be reprogrammed unless you need to install a different variant of the bootloader, or program an app to the Seed's internal flash. + +## Connecting to the Program + +Once the program has been flashed to the Daisy, you'll see that the Seed's USR LED is blinking at a steady rate. +You can push each of the tactile switches to see the corresponding LED illuminate. + +The CV outputs will be generating slow ramp and saw waveforms respectively, MIDI note messages to the MIDI Input will emit from the MIDI output, and audio sent to the audio inputs will be copied to the outputs. + +You can connect to the program using a serial monitor, and see print statements that occur whenever any input is changed. + +Within the source code you'll see that many of these print statements are set within on change callbacks in the `main_page.h`. +Other inputs are checked in the Audio Callback, and messages are generated to be sent from the main `while()` loop. diff --git a/examples/devkits/Desktop-DevKit-UI-Template/src/main.cpp b/examples/devkits/Desktop-DevKit-UI-Template/src/main.cpp new file mode 100644 index 000000000..af47c383b --- /dev/null +++ b/examples/devkits/Desktop-DevKit-UI-Template/src/main.cpp @@ -0,0 +1,230 @@ +/** Desktop DevKit UI Template + * + * UI template program for the Desktop DevKit + * + * This program uses the libDaisy UI framework to generate events from the input + * that can be handled within UI pages. + * This is a bit more complex than the simpler approach to handling UI in other examples, + * but provides a lot of flexibility for more involved applications. + * + * Since the Desktop DevKit is USB powered via the port on the devkit, this build uses the + * external variant of the bootloader so that the seed on the devkit can be reprogrammed + * while connected to the single USB port on the desktop devkit. + * + * This program: + * - initializes the Desktop DevKit hardware + * - starts an audio callback to do pass through, update the controls, and generate UI events + * - starts a low-priority callback to process the UI events + * - prints input data from the `main_page.h` event hooks over USB serial + */ +#include "desktop_devkit.h" +#include "userinterface.h" + +using namespace daisy; +using namespace daisy::desktop_devkit; + +/** Naive hysteresis filter for printing CV input changes + * + * Only update the value if the input has changed by enough to print. +*/ +struct CvChangeFilter +{ + float prev_val; + bool changed; + + /** simple constructor */ + CvChangeFilter() : prev_val(0.f), changed(false) {} + + /** compares the input to the last value output, and updates it if it exceeds a threshold of 0.1 */ + inline float Process(const float in) + { + changed = false; + if(std::abs(in - prev_val) > 0.01f) + { + prev_val = in; + changed = true; + } + return prev_val; + } + + /** returns true the value changed last time `Process` was called */ + inline bool Changed() const { return changed; } +}; + +/** Global Hardware object */ +Hardware hw; + +/** Global UI object */ +Ui ui; + +/** FIFO of strings that we can use to move messages from the Audio callback + * to be printed in the main while() loop. + */ +FIFO, 16> msg_fifo; + +/** state of 3-way toggle for output when changed */ +int prev_toggle_pos = 0; + +/** Simple filters for CV inputs to only output values when they have changed */ +CvChangeFilter cv_change_filt[2]; + +void AudioCallback(AudioHandle::InputBuffer in, + AudioHandle::OutputBuffer out, + size_t size) +{ + hw.UpdateAllControls(); + ui.GenerateEvents(); + + // Here we'll send some strings based on events not covered in the UI. + // + // Certain things (e.g. gate inputs, CV inputs, etc.) often make more sense to + // handle within the audio callback so that there is a new value once per callback, + // syncronized with the block of audio it was read in. + // + // A few of these (e.g. toggles) could be handled in the UI pages. + + // Gate Inputs + if(hw.gate_in[0].Trig()) + msg_fifo.PushBack("Gate In 1: Trig!"); + if(hw.gate_in[1].Trig()) + msg_fifo.PushBack("Gate In 2: Trig!"); + + // Input detection changes + if(hw.sd_detect.FallingEdge()) + msg_fifo.PushBack("SD card removed"); + else if(hw.sd_detect.RisingEdge()) + msg_fifo.PushBack("SD card inserted"); + + if(hw.left_detect.FallingEdge()) + msg_fifo.PushBack("Left input removed"); + else if(hw.left_detect.RisingEdge()) + msg_fifo.PushBack("Left input inserted"); + + if(hw.right_detect.FallingEdge()) + msg_fifo.PushBack("Right input removed"); + else if(hw.right_detect.RisingEdge()) + msg_fifo.PushBack("Right input inserted"); + + // 2-way Toggle + if(hw.tog_sw17.FallingEdge()) + msg_fifo.PushBack("SW17: Down"); + else if(hw.tog_sw17.RisingEdge()) + msg_fifo.PushBack("SW17: Up"); + + // 3-way Toggle + auto new_tog_pos = hw.tog_sw18.Read(); + if(prev_toggle_pos != new_tog_pos) + { + switch(new_tog_pos) + { + case Switch3::POS_CENTER: msg_fifo.PushBack("SW18: Center"); break; + case Switch3::POS_UP: msg_fifo.PushBack("SW18: Up"); break; + case Switch3::POS_DOWN: msg_fifo.PushBack("SW18: Down"); break; + default: break; + } + prev_toggle_pos = new_tog_pos; + } + + // CV Inputs + auto cv1 = cv_change_filt[0].Process(hw.cv[0].Value()); + if(cv_change_filt[0].Changed()) + { + FixedCapStr<32> msg("CV1: "); + msg.AppendFloat(cv1); + msg_fifo.PushBack(msg); + } + auto cv2 = cv_change_filt[1].Process(hw.cv[1].Value()); + if(cv_change_filt[1].Changed()) + { + FixedCapStr<32> msg("CV2: "); + msg.AppendFloat(cv2); + msg_fifo.PushBack(msg); + } + + // Audio pass through + for(size_t i = 0; i < size; i++) + { + out[0][i] = in[0][i]; + out[1][i] = in[1][i]; + } +} + + +/** This callback happens every 4ms (250Hz) and can be interrupted by + * everything except for the SysTick interrupt. + * The frequency of this callback is set in the `Hardware::StartLowPriorityCallback` + * parameters. + * + * Handling the UI events here means that anything we do in the main while() + * loop that may take an indeterminate time (file system I/O, QSPI Saving, etc.) + * won't cause the UI to stall during those processes +*/ +void LowPriorityCallback(void *data) +{ + // Handles events, and redraws the current UI pages + ui.DoEvents(); +} + +int main(void) +{ + hw.Init(); + System::Delay(50); + Logger::StartLog(false); + ui.Init(&hw); + + hw.StartLowPriorityCallback(LowPriorityCallback, 250); + hw.seed.StartAudio(AudioCallback); + + auto last_dac_write = System::GetNow(); + uint16_t dac_value = 0; + + while(true) + { + auto now = System::GetNow(); + + /** Handle MIDI events */ + while(hw.midi.HasEvents()) + { + auto msg = hw.midi.PopEvent(); + switch(msg.type) + { + case NoteOn: + // Echo note on messages to the MIDI out + { + uint8_t bytes[3] = {0x90, 0x00, 0x00}; + bytes[1] = msg.data[0]; + bytes[2] = msg.data[1]; + hw.midi.SendMessage(bytes, 3); + } + break; + default: break; + } + } + + /** Write a ramp (cv out 1) and saw (cv out 2) waveform to the DAC outputs + * Approx. 2.5s period for waveform (0.005s * (4096 / 8)) = 2.56s + */ + if(now - last_dac_write > 5) + { + dac_value += 8; + if(dac_value > 4095) + { + dac_value = 0; + } + hw.SetDacOut(DacHandle::Channel::ONE, dac_value); + hw.SetDacOut(DacHandle::Channel::TWO, 4095 - dac_value); + last_dac_write = now; + } + + /** Print messages from the audio callback */ + while(!msg_fifo.IsEmpty()) + { + auto msg = msg_fifo.PopFront(); + Logger::PrintLine(msg.Cstr()); + } + + System::Delay(1); + } + + return 0; +} \ No newline at end of file diff --git a/examples/devkits/Desktop-DevKit-UI-Template/src/main_page.h b/examples/devkits/Desktop-DevKit-UI-Template/src/main_page.h new file mode 100644 index 000000000..125ca4e8a --- /dev/null +++ b/examples/devkits/Desktop-DevKit-UI-Template/src/main_page.h @@ -0,0 +1,56 @@ +#pragma once + +#include "daisy.h" + +class MainPage : public daisy::UiPage +{ + public: + /** Simple alias for logging + * StartLog() for the destination should have already been called before the + * page is opened. + */ + using Log = daisy::Logger; + + void Init() {} + + void Draw(const daisy::UiCanvasDescriptor &canvasDescriptor) override + { + auto *hw = reinterpret_cast( + canvasDescriptor.handle_); + auto now = daisy::System::GetNow(); + hw->seed.SetLed((now & 511) < 255); + + // For now we'll just illuminate each LED with the state of the button + for(size_t i = 0; i < 16; i++) + { + hw->SetLed(i, hw->button[i].Pressed() ? 1.f : 0.f); + } + } + + bool OnButton(uint16_t buttonID, + uint8_t numberOfPresses, + bool isRetriggering) override + { + switch(numberOfPresses) + { + case 0: Log::PrintLine("Released %d", buttonID + 1); break; + case 1: Log::PrintLine("Pressed %d", buttonID + 1); break; + case 2: Log::PrintLine("Long Pressed %d", buttonID + 1); break; + default: break; + } + return false; + } + + bool OnPotMoved(uint16_t potID, float newPosition) + { + // Print Format: "Pot {potID+1}: {newPosition}" + daisy::FixedCapStr<16> valueStr("Pot "); + valueStr.AppendInt(potID + 1); + valueStr.Append(": "); + valueStr.AppendFloat(newPosition, 3); + Log::PrintLine(valueStr.Cstr()); + return false; + } + + void OnShow() { Log::PrintLine("Page Opened!"); } +}; diff --git a/examples/devkits/Desktop-DevKit-UI-Template/src/ui_glue.h b/examples/devkits/Desktop-DevKit-UI-Template/src/ui_glue.h new file mode 100644 index 000000000..a6f1b9ec8 --- /dev/null +++ b/examples/devkits/Desktop-DevKit-UI-Template/src/ui_glue.h @@ -0,0 +1,34 @@ +#pragma once + +#include "desktop_devkit.h" + +static constexpr size_t kLongPressDuration = 1500; + +enum CanvasIds { canvasLedDisplay = 0, NUM_CANVASES }; + +void FlushLeds(const daisy::UiCanvasDescriptor &canvasDescriptor) { + auto *hw = reinterpret_cast( + canvasDescriptor.handle_); + hw->UpdateLeds(); +} + +void ClearLeds(const daisy::UiCanvasDescriptor &canvasDescriptor) { + auto *hw = reinterpret_cast( + canvasDescriptor.handle_); + hw->ClearLeds(); +} + +/** Interface class used for generating UI events from Pot inputs. */ +class PotListener { +public: + /** Initialize the Object */ + void Init(daisy::desktop_devkit::Hardware *hw) { hw_ = hw; } + + /** Read the value from the hardware + * TODO: update to wrapper if add pot min/max calibration + */ + float GetPotValue(uint16_t potId) { return hw_->pot[potId].Value(); } + +private: + daisy::desktop_devkit::Hardware *hw_; +}; diff --git a/examples/devkits/Desktop-DevKit-UI-Template/src/userinterface.h b/examples/devkits/Desktop-DevKit-UI-Template/src/userinterface.h new file mode 100644 index 000000000..4a17b1739 --- /dev/null +++ b/examples/devkits/Desktop-DevKit-UI-Template/src/userinterface.h @@ -0,0 +1,98 @@ +#pragma once +#include "desktop_devkit.h" +#include "main_page.h" +#include "ui_glue.h" + +/** User Inteface for the application. + * + * Initializes the mechanisms for updating the LEDs at a regular interval, + * and generating events from tactile inputs (i.e. pots, buttons). + * + * CVs/Gates do not typically generate UI events because we dont' want to flood + * the event fifo since we want to handle those signals as they arrive from the + * audio callback. It is, however, possible to access the hardware class in the + * `Draw()` method of any UIPage if visualizing those signals is important; it + * should be kept in mind that the period that the Draw method is called is + * often much slower than the rate the inputs actually update. + * + */ +class Ui +{ + public: + void Init(daisy::desktop_devkit::Hardware *hw) + { + hw_ = hw; + + daisy::UI::SpecialControlIds specialControlIds; //< None + daisy::UiCanvasDescriptor ledDisplayDescriptor; + ledDisplayDescriptor.id_ = canvasLedDisplay; + ledDisplayDescriptor.handle_ = hw_; + ledDisplayDescriptor.updateRateMs_ = 16; //< 60Hz + ledDisplayDescriptor.clearFunction_ = ClearLeds; + ledDisplayDescriptor.flushFunction_ = FlushLeds; + + pot_listener_.Init(hw_); + pot_monitor_.Init(event_queue_, + pot_listener_, + 125, + (1.f / (1 << 9)), + (1.f / (1 << 12))); + + // Init the pages: + ui_.Init(event_queue_, + specialControlIds, + {ledDisplayDescriptor}, + canvasLedDisplay); + // ui_.OpenPage(splash_page_); + ui_.OpenPage(main_page_); + } + + void GenerateEvents() + { + // Pot events + pot_monitor_.Process(); + + // Button events + for(size_t i = 0; i < 16; i++) + { + auto *btn = &hw_->button[i]; + if(btn->RisingEdge()) + { + event_queue_.AddButtonPressed(i, 1); + } + else if(btn->Pressed() && btn->TimeHeldMs() > kLongPressDuration) + { + if(!ignore_next_btn_release[i]) + { + event_queue_.AddButtonPressed(i, 2); + ignore_next_btn_release[i] = true; + } + } + else if(btn->FallingEdge()) + { + if(ignore_next_btn_release[i]) + { + ignore_next_btn_release[i] = false; + } + else + { + event_queue_.AddButtonReleased(i); + } + } + } + } + + void DoEvents() { ui_.Process(); } + + private: + daisy::desktop_devkit::Hardware *hw_; + daisy::UI ui_; + + MainPage main_page_; + + /** Event Generation */ + bool ignore_next_btn_release[16]; + daisy::UiEventQueue event_queue_; + PotListener pot_listener_; + daisy::PotMonitor pot_monitor_; +}; diff --git a/src/desktop_devkit.cpp b/src/desktop_devkit.cpp index 17dd4c8c2..9b2beabe6 100644 --- a/src/desktop_devkit.cpp +++ b/src/desktop_devkit.cpp @@ -20,8 +20,17 @@ void Hardware::Init() tog_sw18.Init(daisy::seed::D28, daisy::seed::D27); sd_detect.Init(daisy::seed::D7); - left_detect.Init(daisy::seed::D16); - right_detect.Init(daisy::seed::D17); + + // Initialize jack input detection with opposite polarity since the + // switching connection of the jack is held to GND while it is unplugged. + left_detect.Init(daisy::seed::D16, + 0.f, + Switch::Type::TYPE_MOMENTARY, + Switch::Polarity::POLARITY_NORMAL); + right_detect.Init(daisy::seed::D17, + 0.f, + Switch::Type::TYPE_MOMENTARY, + Switch::Polarity::POLARITY_NORMAL); ButtonSr::Config sr_cfg; sr_cfg.clk = daisy::seed::D8; @@ -96,6 +105,9 @@ void Hardware::UpdateAllControls() for(auto &c : cv) c.Process(); tog_sw17.Debounce(); + sd_detect.Debounce(); + left_detect.Debounce(); + right_detect.Debounce(); } void Hardware::SetDacOut(DacHandle::Channel channel, uint16_t code) From 285726a2e6c046f599b26609d281d102871268a9 Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Wed, 23 Sep 2026 16:40:05 -0700 Subject: [PATCH 07/12] fixed devkit styling issues --- src/desktop_devkit.h | 2 +- src/eurorack_devkit.cpp | 181 ++++++++++++++++++++++------------------ src/eurorack_devkit.h | 81 +++++++++--------- src/pedal_devkit.cpp | 152 +++++++++++++++++---------------- 4 files changed, 222 insertions(+), 194 deletions(-) diff --git a/src/desktop_devkit.h b/src/desktop_devkit.h index 3c6ec8791..5049b2fc4 100644 --- a/src/desktop_devkit.h +++ b/src/desktop_devkit.h @@ -64,7 +64,7 @@ class Hardware */ void StartLowPriorityCallback(TimerHandle::PeriodElapsedCallback cb, uint32_t target_freq, - void * data = nullptr); + void* data = nullptr); /** Stops an ongoing low-priority callback */ void StopLowPriorityCallback(); diff --git a/src/eurorack_devkit.cpp b/src/eurorack_devkit.cpp index 77deea13c..9ce7ca34d 100644 --- a/src/eurorack_devkit.cpp +++ b/src/eurorack_devkit.cpp @@ -1,100 +1,117 @@ #include "eurorack_devkit.h" -namespace daisy::eurorack_devkit { +namespace daisy::eurorack_devkit +{ +void Hardware::Init() +{ + seed.Init(true); + sw1.Init(seed::D0); + sw2.Init(seed::D20); + sw3.Init(seed::D7, seed::D27); //< wired opposite from expected.. + sw4.Init(seed::D12); -void Hardware::Init() { - seed.Init(true); - sw1.Init(seed::D0); - sw2.Init(seed::D20); - sw3.Init(seed::D7, seed::D27); //< wired opposite from expected.. - sw4.Init(seed::D12); + AdcChannelConfig adc_config[5]; + auto conversion_speed + = AdcChannelConfig::ConversionSpeed::SPEED_810CYCLES_5; + adc_config[0].InitMux( + seed::D15, 8, seed::D24, seed::D25, seed::D26, conversion_speed); + adc_config[1].InitSingle(seed::D18, conversion_speed); + adc_config[2].InitSingle(seed::D17, conversion_speed); + adc_config[3].InitSingle(seed::D16, conversion_speed); + adc_config[4].InitSingle(seed::D19, conversion_speed); + seed.adc.Init(adc_config, 5); + for(size_t i = 0; i < kNumPots; i++) + { + pot[i].Init(seed.adc.GetMuxPtr(0, i), 1000.f); + } + for(size_t i = 0; i < kNumCVs; i++) + { + cv[i].InitBipolarCv(seed.adc.GetPtr(i + 1), 1000.f); + } - AdcChannelConfig adc_config[5]; - auto conversion_speed = AdcChannelConfig::ConversionSpeed::SPEED_810CYCLES_5; - adc_config[0].InitMux(seed::D15, 8, seed::D24, seed::D25, seed::D26, - conversion_speed); - adc_config[1].InitSingle(seed::D18, conversion_speed); - adc_config[2].InitSingle(seed::D17, conversion_speed); - adc_config[3].InitSingle(seed::D16, conversion_speed); - adc_config[4].InitSingle(seed::D19, conversion_speed); - seed.adc.Init(adc_config, 5); - for (size_t i = 0; i < kNumPots; i++) { - pot[i].Init(seed.adc.GetMuxPtr(0, i), 1000.f); - } - for (size_t i = 0; i < kNumCVs; i++) { - cv[i].InitBipolarCv(seed.adc.GetPtr(i + 1), 1000.f); - } + led1.Init(seed::D9, seed::D28, seed::D8, false); + led2.Init(seed::D11, false); - led1.Init(seed::D9, seed::D28, seed::D8, false); - led2.Init(seed::D11, false); + gate_in1.Init(seed::D10); + gate_in2.Init(seed::D21); - gate_in1.Init(seed::D10); - gate_in2.Init(seed::D21); + // DAC init + // Maybe this becomes separate and/or optional to make it + // easier to set up these outputs as GPIO if the user wants? + DacHandle::Config dac_config; + dac_config.bitdepth = DacHandle::BitDepth::BITS_12; + dac_config.buff_state = DacHandle::BufferState::DISABLED; + dac_config.mode = DacHandle::Mode::POLLING; + dac_config.chn = DacHandle::Channel::BOTH; + seed.dac.Init(dac_config); - // DAC init - // Maybe this becomes separate and/or optional to make it - // easier to set up these outputs as GPIO if the user wants? - DacHandle::Config dac_config; - dac_config.bitdepth = DacHandle::BitDepth::BITS_12; - dac_config.buff_state = DacHandle::BufferState::DISABLED; - dac_config.mode = DacHandle::Mode::POLLING; - dac_config.chn = DacHandle::Channel::BOTH; - seed.dac.Init(dac_config); + MidiUartHandler::Config midi_config; + midi_config.transport_config.periph + = UartHandler::Config::Peripheral::USART_1; + midi_config.transport_config.rx = seed::D14; + midi_config.transport_config.tx = seed::D13; + midi.Init(midi_config); - MidiUartHandler::Config midi_config; - midi_config.transport_config.periph = - UartHandler::Config::Peripheral::USART_1; - midi_config.transport_config.rx = seed::D14; - midi_config.transport_config.tx = seed::D13; - midi.Init(midi_config); - - seed.adc.Start(); + seed.adc.Start(); } -void Hardware::UpdateAllControls() { - for (auto &p : pot) - p.Process(); - for (auto &c : cv) - c.Process(); - sw1.Debounce(); - sw2.Debounce(); - sw4.Debounce(); +void Hardware::UpdateAllControls() +{ + for(auto &p : pot) + p.Process(); + for(auto &c : cv) + c.Process(); + sw1.Debounce(); + sw2.Debounce(); + sw4.Debounce(); } -void Hardware::SetDacOut(DacHandle::Channel channel, uint16_t code) { - seed.dac.WriteValue(channel, code); +void Hardware::SetDacOut(DacHandle::Channel channel, uint16_t code) +{ + seed.dac.WriteValue(channel, code); } -void Hardware::PrintAllControls() { - // TODO: consider updating this to write everything to one buffer, and then - // transmit to avoid the screen flicker of everything writing in separate - // transactions. - using Log = Logger; - const char *sw3_str = sw3.Read() == Switch3::POS_LEFT - ? "L" - : sw3.Read() == Switch3::POS_RIGHT ? "R" : "C"; +void Hardware::PrintAllControls() +{ + // TODO: consider updating this to write everything to one buffer, and then + // transmit to avoid the screen flicker of everything writing in separate + // transactions. + using Log = Logger; + const char *sw3_str = sw3.Read() == Switch3::POS_LEFT + ? "L" + : sw3.Read() == Switch3::POS_RIGHT ? "R" : "C"; - Log::PrintLine("\033[2J\033[H"); //< Clear the terminal - Log::PrintLine("Pedal DevKit Controls:"); - Log::PrintLine("----Switches----"); - Log::PrintLine("\tSW1: %s\tSW2: %s\tSW3: %s", sw1.Pressed() ? "X" : "O", - sw2.Pressed() ? "X" : "O", sw3_str, sw4.Pressed() ? "R" : "L"); - Log::PrintLine("----Gate Ins----"); - Log::PrintLine("\tGate In 1: %s\tGate In 2: %s", gate_in1.State() ? "X" : "O", - gate_in2.State() ? "X" : "O"); - Log::PrintLine("------ADCs------"); - Log::PrintLine("\tVR1: " FLT_FMT3 "\tVR2: " FLT_FMT3 "\tVR3: " FLT_FMT3 - "\tVR4: " FLT_FMT3, - FLT_VAR3(pot[0].Value()), FLT_VAR3(pot[1].Value()), - FLT_VAR3(pot[2].Value()), FLT_VAR3(pot[3].Value())); - Log::PrintLine("\tVR5: " FLT_FMT3 "\tVR6: " FLT_FMT3 "\tVR7: " FLT_FMT3 - "\tVR8: " FLT_FMT3, - FLT_VAR3(pot[4].Value()), FLT_VAR3(pot[5].Value()), - FLT_VAR3(pot[6].Value()), FLT_VAR3(pot[7].Value())); - Log::PrintLine("\tCV 1: " FLT_FMT3 "\tCV 2: " FLT_FMT3 "\tCV 3: " FLT_FMT3 - "\tCV 4: " FLT_FMT3, - FLT_VAR3(cv[0].Value()), FLT_VAR3(cv[1].Value()), - FLT_VAR3(cv[2].Value()), FLT_VAR3(cv[3].Value())); + Log::PrintLine("\033[2J\033[H"); //< Clear the terminal + Log::PrintLine("Pedal DevKit Controls:"); + Log::PrintLine("----Switches----"); + Log::PrintLine("\tSW1: %s\tSW2: %s\tSW3: %s", + sw1.Pressed() ? "X" : "O", + sw2.Pressed() ? "X" : "O", + sw3_str, + sw4.Pressed() ? "R" : "L"); + Log::PrintLine("----Gate Ins----"); + Log::PrintLine("\tGate In 1: %s\tGate In 2: %s", + gate_in1.State() ? "X" : "O", + gate_in2.State() ? "X" : "O"); + Log::PrintLine("------ADCs------"); + Log::PrintLine("\tVR1: " FLT_FMT3 "\tVR2: " FLT_FMT3 "\tVR3: " FLT_FMT3 + "\tVR4: " FLT_FMT3, + FLT_VAR3(pot[0].Value()), + FLT_VAR3(pot[1].Value()), + FLT_VAR3(pot[2].Value()), + FLT_VAR3(pot[3].Value())); + Log::PrintLine("\tVR5: " FLT_FMT3 "\tVR6: " FLT_FMT3 "\tVR7: " FLT_FMT3 + "\tVR8: " FLT_FMT3, + FLT_VAR3(pot[4].Value()), + FLT_VAR3(pot[5].Value()), + FLT_VAR3(pot[6].Value()), + FLT_VAR3(pot[7].Value())); + Log::PrintLine("\tCV 1: " FLT_FMT3 "\tCV 2: " FLT_FMT3 "\tCV 3: " FLT_FMT3 + "\tCV 4: " FLT_FMT3, + FLT_VAR3(cv[0].Value()), + FLT_VAR3(cv[1].Value()), + FLT_VAR3(cv[2].Value()), + FLT_VAR3(cv[3].Value())); } } // namespace daisy::eurorack_devkit \ No newline at end of file diff --git a/src/eurorack_devkit.h b/src/eurorack_devkit.h index 1bf00f34f..bf2f5b44c 100644 --- a/src/eurorack_devkit.h +++ b/src/eurorack_devkit.h @@ -2,57 +2,58 @@ #include "daisy_seed.h" -namespace daisy::eurorack_devkit { - -class Hardware { -public: - Hardware() {} - - /** Number of Pots on the DevKit */ - inline static constexpr size_t kNumPots = 8; - /** Number of CV inputs on the DevKit */ - inline static constexpr size_t kNumCVs = 4; - - // SOM - DaisySeed seed; - // Tactile Switches - Switch sw1, sw2; - // Toggle Switches - Switch3 sw3; - Switch sw4; - // Pots - AnalogControl pot[kNumPots]; - // Bipolar CV Inputs - AnalogControl cv[kNumCVs]; - // Gate Inputs - GateIn gate_in1, gate_in2; - // MIDI - MidiUartHandler midi; - - // LEDs - RgbLed led1; - Led led2; - - /** Initialize the hardware */ - void Init(); - - /** Process all analog inputs, debounce digital inputs, and update their +namespace daisy::eurorack_devkit +{ +class Hardware +{ + public: + Hardware() {} + + /** Number of Pots on the DevKit */ + inline static constexpr size_t kNumPots = 8; + /** Number of CV inputs on the DevKit */ + inline static constexpr size_t kNumCVs = 4; + + // SOM + DaisySeed seed; + // Tactile Switches + Switch sw1, sw2; + // Toggle Switches + Switch3 sw3; + Switch sw4; + // Pots + AnalogControl pot[kNumPots]; + // Bipolar CV Inputs + AnalogControl cv[kNumCVs]; + // Gate Inputs + GateIn gate_in1, gate_in2; + // MIDI + MidiUartHandler midi; + + // LEDs + RgbLed led1; + Led led2; + + /** Initialize the hardware */ + void Init(); + + /** Process all analog inputs, debounce digital inputs, and update their * internally stored states. */ - void UpdateAllControls(); + void UpdateAllControls(); - /** Write the code to the DAC output + /** Write the code to the DAC output * @param channel DAC channel to write to * @param code the 0-4096 code to write corresponding to the output voltage */ - void SetDacOut(DacHandle::Channel channel, uint16_t code); + void SetDacOut(DacHandle::Channel channel, uint16_t code); - /** Print the state of all hardware inputs in a human readable block over + /** Print the state of all hardware inputs in a human readable block over * serial using the Seed's built-in USB port. * * Start the Seed's logger with `seed.StartLog()` prior to using this method. */ - void PrintAllControls(); + void PrintAllControls(); }; } // namespace daisy::eurorack_devkit diff --git a/src/pedal_devkit.cpp b/src/pedal_devkit.cpp index e24599da2..d7d1501ba 100644 --- a/src/pedal_devkit.cpp +++ b/src/pedal_devkit.cpp @@ -1,87 +1,97 @@ #include "pedal_devkit.h" -namespace daisy::pedal_devkit { +namespace daisy::pedal_devkit +{ +void Hardware::Init() +{ + seed.Init(true); + sw1.Init(seed::D7, seed::D8); //< wired opposite from expected.. + sw2.Init(seed::D9); + sw3.Init(seed::D22); + sw4.Init(seed::D0); + sw5.Init(seed::D28); + fsw_1.Init(seed::D10); + fsw_2.Init(seed::D23); + sd_detect.Init(seed::D11); -void Hardware::Init() { - seed.Init(true); - sw1.Init(seed::D7, seed::D8); //< wired opposite from expected.. - sw2.Init(seed::D9); - sw3.Init(seed::D22); - sw4.Init(seed::D0); - sw5.Init(seed::D28); - fsw_1.Init(seed::D10); - fsw_2.Init(seed::D23); - sd_detect.Init(seed::D11); + AdcChannelConfig adc_cfg[kNumPots + 1]; + auto conversion_speed + = AdcChannelConfig::ConversionSpeed::SPEED_810CYCLES_5; + // Pots + adc_cfg[0].InitSingle(seed::D15, conversion_speed); + adc_cfg[1].InitSingle(seed::D16, conversion_speed); + adc_cfg[2].InitSingle(seed::D17, conversion_speed); + adc_cfg[3].InitSingle(seed::D18, conversion_speed); + adc_cfg[4].InitSingle(seed::D19, conversion_speed); + adc_cfg[5].InitSingle(seed::D20, conversion_speed); + // Expression + adc_cfg[6].InitSingle(seed::D21, conversion_speed); + seed.adc.Init(adc_cfg, kNumPots + 1); - AdcChannelConfig adc_cfg[kNumPots + 1]; - auto conversion_speed = AdcChannelConfig::ConversionSpeed::SPEED_810CYCLES_5; - // Pots - adc_cfg[0].InitSingle(seed::D15, conversion_speed); - adc_cfg[1].InitSingle(seed::D16, conversion_speed); - adc_cfg[2].InitSingle(seed::D17, conversion_speed); - adc_cfg[3].InitSingle(seed::D18, conversion_speed); - adc_cfg[4].InitSingle(seed::D19, conversion_speed); - adc_cfg[5].InitSingle(seed::D20, conversion_speed); - // Expression - adc_cfg[6].InitSingle(seed::D21, conversion_speed); - seed.adc.Init(adc_cfg, kNumPots + 1); + for(size_t i = 0; i < kNumPots; i++) + pot[i].Init(seed.adc.GetPtr(i), 1000.f); + expression.Init(seed.adc.GetPtr(kNumPots), 1000.f); - for (size_t i = 0; i < kNumPots; i++) - pot[i].Init(seed.adc.GetPtr(i), 1000.f); - expression.Init(seed.adc.GetPtr(kNumPots), 1000.f); + led1.Init(seed::D24, false); + led2.Init(seed::D25, seed::D27, seed::D26, false); - led1.Init(seed::D24, false); - led2.Init(seed::D25, seed::D27, seed::D26, false); + MidiUartHandler::Config midi_config; + midi_config.transport_config.periph + = UartHandler::Config::Peripheral::USART_1; + midi_config.transport_config.rx = seed::D14; + midi_config.transport_config.tx = seed::D13; + midi.Init(midi_config); - MidiUartHandler::Config midi_config; - midi_config.transport_config.periph = - UartHandler::Config::Peripheral::USART_1; - midi_config.transport_config.rx = seed::D14; - midi_config.transport_config.tx = seed::D13; - midi.Init(midi_config); - - seed.adc.Start(); + seed.adc.Start(); } -void Hardware::UpdateAllControls() { - for (auto &p : pot) - p.Process(); - expression.Process(); +void Hardware::UpdateAllControls() +{ + for(auto &p : pot) + p.Process(); + expression.Process(); - sw2.Debounce(); - sw3.Debounce(); - sw4.Debounce(); - sw5.Debounce(); - fsw_1.Debounce(); - fsw_2.Debounce(); - sd_detect.Debounce(); + sw2.Debounce(); + sw3.Debounce(); + sw4.Debounce(); + sw5.Debounce(); + fsw_1.Debounce(); + fsw_2.Debounce(); + sd_detect.Debounce(); } -void Hardware::PrintAllControls() { - using Log = Logger; - const char *sw1_str = sw1.Read() == Switch3::POS_LEFT - ? "L" - : sw1.Read() == Switch3::POS_RIGHT ? "R" : "C"; +void Hardware::PrintAllControls() +{ + using Log = Logger; + const char *sw1_str = sw1.Read() == Switch3::POS_LEFT + ? "L" + : sw1.Read() == Switch3::POS_RIGHT ? "R" : "C"; - Log::PrintLine("\033[2J\033[H]"); //< Clear the terminal - Log::PrintLine("Pedal DevKit Controls:"); - Log::PrintLine("----Switches----"); - Log::PrintLine("\tSW1: %s\tSW2: %s\tSW3: %s", sw1_str, - sw2.Pressed() ? "R" : "L", sw3.Pressed() ? "R" : "L"); - Log::PrintLine("\tSW4: %s\tSW5: %s", sw4.Pressed() ? "X" : "O", - sw5.Pressed() ? "X" : "O"); - Log::PrintLine("\tFSW1: %s\tFSW2: %s", fsw_1.Pressed() ? "X" : "O", - fsw_2.Pressed() ? "X" : "O"); - Log::PrintLine("\tSD Detect: %s", - sd_detect.Pressed() ? "SD Card Detected" : "No SD Card"); - Log::PrintLine("------ADCs------"); - Log::PrintLine("\tVR1: " FLT_FMT3 "\tVR2: " FLT_FMT3 "\tVR3: " FLT_FMT3, - FLT_VAR3(pot[0].Value()), FLT_VAR3(pot[1].Value()), - FLT_VAR3(pot[2].Value())); - Log::PrintLine("\tVR4: " FLT_FMT3 "\tVR5: " FLT_FMT3 "\tVR6: " FLT_FMT3, - FLT_VAR3(pot[3].Value()), FLT_VAR3(pot[4].Value()), - FLT_VAR3(pot[5].Value())); - Log::PrintLine("\tExpression: " FLT_FMT3, FLT_VAR3(expression.Value())); + Log::PrintLine("\033[2J\033[H]"); //< Clear the terminal + Log::PrintLine("Pedal DevKit Controls:"); + Log::PrintLine("----Switches----"); + Log::PrintLine("\tSW1: %s\tSW2: %s\tSW3: %s", + sw1_str, + sw2.Pressed() ? "R" : "L", + sw3.Pressed() ? "R" : "L"); + Log::PrintLine("\tSW4: %s\tSW5: %s", + sw4.Pressed() ? "X" : "O", + sw5.Pressed() ? "X" : "O"); + Log::PrintLine("\tFSW1: %s\tFSW2: %s", + fsw_1.Pressed() ? "X" : "O", + fsw_2.Pressed() ? "X" : "O"); + Log::PrintLine("\tSD Detect: %s", + sd_detect.Pressed() ? "SD Card Detected" : "No SD Card"); + Log::PrintLine("------ADCs------"); + Log::PrintLine("\tVR1: " FLT_FMT3 "\tVR2: " FLT_FMT3 "\tVR3: " FLT_FMT3, + FLT_VAR3(pot[0].Value()), + FLT_VAR3(pot[1].Value()), + FLT_VAR3(pot[2].Value())); + Log::PrintLine("\tVR4: " FLT_FMT3 "\tVR5: " FLT_FMT3 "\tVR6: " FLT_FMT3, + FLT_VAR3(pot[3].Value()), + FLT_VAR3(pot[4].Value()), + FLT_VAR3(pot[5].Value())); + Log::PrintLine("\tExpression: " FLT_FMT3, FLT_VAR3(expression.Value())); } } // namespace daisy::pedal_devkit \ No newline at end of file From a140788fb454e8b9ed942a00c607501c0900a989 Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Thu, 24 Sep 2026 09:29:05 -0700 Subject: [PATCH 08/12] reverted back to C++14, and moved inline constexpr to be namespace level constexpr for each devkit. --- CMakeLists.txt | 2 +- Makefile | 2 +- core/Makefile | 2 +- src/eurorack_devkit.h | 10 +++++----- src/pedal_devkit.h | 5 +++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7e54588c..b2bb90a39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,7 +134,7 @@ target_compile_options(daisy PRIVATE ) set_target_properties(daisy PROPERTIES - CXX_STANDARD 17 + CXX_STANDARD 14 CXX_STANDARD_REQUIRED C_STANDARD 11 C_STANDARD_REQUIRED diff --git a/Makefile b/Makefile index 4e8b1b92e..5253e570e 100644 --- a/Makefile +++ b/Makefile @@ -348,7 +348,7 @@ CPPFLAGS += \ -fno-rtti C_STANDARD = -std=gnu11 -CPP_STANDARD += -std=gnu++17 +CPP_STANDARD += -std=gnu++14 # default action: build all all: $(BUILD_DIR)/$(TARGET).a diff --git a/core/Makefile b/core/Makefile index d8d774425..d6619f8a6 100644 --- a/core/Makefile +++ b/core/Makefile @@ -202,7 +202,7 @@ CPPFLAGS += \ -Wno-register C_STANDARD = -std=gnu11 -CPP_STANDARD ?= -std=gnu++17 +CPP_STANDARD ?= -std=gnu++14 ####################################### diff --git a/src/eurorack_devkit.h b/src/eurorack_devkit.h index bf2f5b44c..d50eb2ecf 100644 --- a/src/eurorack_devkit.h +++ b/src/eurorack_devkit.h @@ -4,16 +4,16 @@ namespace daisy::eurorack_devkit { +/** Number of Pots on the DevKit */ +constexpr size_t kNumPots = 8; +/** Number of CV inputs on the DevKit */ +constexpr size_t kNumCVs = 4; + class Hardware { public: Hardware() {} - /** Number of Pots on the DevKit */ - inline static constexpr size_t kNumPots = 8; - /** Number of CV inputs on the DevKit */ - inline static constexpr size_t kNumCVs = 4; - // SOM DaisySeed seed; // Tactile Switches diff --git a/src/pedal_devkit.h b/src/pedal_devkit.h index 18d4438f6..6488f927d 100644 --- a/src/pedal_devkit.h +++ b/src/pedal_devkit.h @@ -4,6 +4,9 @@ namespace daisy::pedal_devkit { +/** Number of Pots on the DevKit */ +constexpr size_t kNumPots = 6; + /** Board support for the Pedal DevKit * * Provides access to all HW on the DevKit with convenience methods for common @@ -17,8 +20,6 @@ class Hardware // SOM DaisySeed seed; - /** Number of Pots on the DevKit */ - inline static constexpr size_t kNumPots = 6; // Analog Inputs /** Pot inputs. Labeled VR1 through VR6 on the PCB. */ From 39ce7bfabdbc4d2c3795af53c4bfcdf8f8d75f05 Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Thu, 24 Sep 2026 09:39:47 -0700 Subject: [PATCH 09/12] added consts for component quantities (kNumPots, kNumButtons, etc.) to desktop devkit to match other boards. --- .../Desktop-DevKit-UI-Template/src/main_page.h | 8 ++++---- .../src/userinterface.h | 11 ++++++----- src/desktop_devkit.cpp | 8 ++++---- src/desktop_devkit.h | 17 ++++++++++++++--- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/examples/devkits/Desktop-DevKit-UI-Template/src/main_page.h b/examples/devkits/Desktop-DevKit-UI-Template/src/main_page.h index 125ca4e8a..f9d15444b 100644 --- a/examples/devkits/Desktop-DevKit-UI-Template/src/main_page.h +++ b/examples/devkits/Desktop-DevKit-UI-Template/src/main_page.h @@ -6,9 +6,9 @@ class MainPage : public daisy::UiPage { public: /** Simple alias for logging - * StartLog() for the destination should have already been called before the - * page is opened. - */ + * StartLog() for the destination should have already been called before the + * page is opened. + */ using Log = daisy::Logger; void Init() {} @@ -21,7 +21,7 @@ class MainPage : public daisy::UiPage hw->seed.SetLed((now & 511) < 255); // For now we'll just illuminate each LED with the state of the button - for(size_t i = 0; i < 16; i++) + for(size_t i = 0; i < daisy::desktop_devkit::kNumLeds; i++) { hw->SetLed(i, hw->button[i].Pressed() ? 1.f : 0.f); } diff --git a/examples/devkits/Desktop-DevKit-UI-Template/src/userinterface.h b/examples/devkits/Desktop-DevKit-UI-Template/src/userinterface.h index 4a17b1739..855872f15 100644 --- a/examples/devkits/Desktop-DevKit-UI-Template/src/userinterface.h +++ b/examples/devkits/Desktop-DevKit-UI-Template/src/userinterface.h @@ -53,7 +53,7 @@ class Ui pot_monitor_.Process(); // Button events - for(size_t i = 0; i < 16; i++) + for(size_t i = 0; i < daisy::desktop_devkit::kNumButtons; i++) { auto *btn = &hw_->button[i]; if(btn->RisingEdge()) @@ -91,8 +91,9 @@ class Ui MainPage main_page_; /** Event Generation */ - bool ignore_next_btn_release[16]; - daisy::UiEventQueue event_queue_; - PotListener pot_listener_; - daisy::PotMonitor pot_monitor_; + bool ignore_next_btn_release[daisy::desktop_devkit::kNumButtons]; + daisy::UiEventQueue event_queue_; + PotListener pot_listener_; + daisy::PotMonitor + pot_monitor_; }; diff --git a/src/desktop_devkit.cpp b/src/desktop_devkit.cpp index 9b2beabe6..839b25a75 100644 --- a/src/desktop_devkit.cpp +++ b/src/desktop_devkit.cpp @@ -53,7 +53,7 @@ void Hardware::Init() auto conversion_speed = daisy::AdcChannelConfig::ConversionSpeed::SPEED_810CYCLES_5; adc_cfg[0].InitMux(daisy::seed::D15, - 8, + kNumPots, daisy::seed::D24, daisy::seed::D25, daisy::seed::D26, @@ -62,9 +62,9 @@ void Hardware::Init() adc_cfg[2].InitSingle(daisy::seed::D21, conversion_speed); seed.adc.Init(adc_cfg, 3); - for(int i = 0; i < 8; i++) + for(int i = 0; i < kNumPots; i++) pot[i].Init(seed.adc.GetMuxPtr(0, i), 1000.f); - for(int i = 0; i < 2; i++) + for(int i = 0; i < kNumCVs; i++) cv[i].InitBipolarCv(seed.adc.GetPtr(i + 1), 1000.f); /** Leds */ @@ -95,7 +95,7 @@ void Hardware::Init() void Hardware::UpdateAllControls() { button_sr.Update(); - for(int i = 0; i < 16; i++) + for(int i = 0; i < kNumButtons; i++) { int sr_idx = 15 - i; button[i].Debounce(button_sr.State(sr_idx)); diff --git a/src/desktop_devkit.h b/src/desktop_devkit.h index 5049b2fc4..12950a9ea 100644 --- a/src/desktop_devkit.h +++ b/src/desktop_devkit.h @@ -3,6 +3,17 @@ namespace daisy::desktop_devkit { +/** Number of Pots on the DevKit */ +constexpr size_t kNumPots = 8; +/** Number of CV inputs on the DevKit */ +constexpr size_t kNumCVs = 2; +/** Number of Gate inputs on the DevKit */ +constexpr size_t kNumGateIns = 2; +/** Number of push buttons on the DevKit */ +constexpr size_t kNumButtons = 16; +/** Number of push buttons on the DevKit */ +constexpr size_t kNumLeds = 16; + class Hardware { public: @@ -15,9 +26,9 @@ class Hardware Switch tog_sw17; Switch3 tog_sw18; ButtonSr button_sr; - GateIn gate_in[2]; - AnalogControl pot[8], cv[2]; - DigitalControl button[16]; + GateIn gate_in[kNumGateIns]; + AnalogControl pot[kNumPots], cv[kNumCVs]; + DigitalControl button[kNumButtons]; MidiUartHandler midi; LedDriver led_driver; TimerHandle tim5_handle; From 3a276870bc4628040d5b8f67704b5a09743787ca Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Thu, 24 Sep 2026 09:43:14 -0700 Subject: [PATCH 10/12] cleanup new example Makefiles. --- examples/devkits/Desktop-DevKit-UI-Template/Makefile | 4 ++-- examples/devkits/Eurorack-DevKit-Template/Makefile | 8 ++------ examples/devkits/Pedal-DevKit-Template/Makefile | 2 -- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/examples/devkits/Desktop-DevKit-UI-Template/Makefile b/examples/devkits/Desktop-DevKit-UI-Template/Makefile index 9a7acddfd..a38a007c4 100644 --- a/examples/devkits/Desktop-DevKit-UI-Template/Makefile +++ b/examples/devkits/Desktop-DevKit-UI-Template/Makefile @@ -14,8 +14,6 @@ APP_TYPE=BOOT_SRAM # Sources CPP_SOURCES = src/main.cpp -#C_INCLUDES += -I./include/ - LIBDAISY_DIR = ../../../ # (optional) Add DaisySP @@ -28,6 +26,8 @@ USE_FATFS = 1 # Core location, and generic Makefile. SYSTEM_FILES_DIR = $(LIBDAISY_DIR)/core +# Use the bootloader variant that allows programming DFU over the +# external USB port (used to power the devkit). BOOT_BIN=$(SYSTEM_FILES_DIR)/dsy_bootloader_v6_4-extdfu-2000ms.bin include $(SYSTEM_FILES_DIR)/Makefile diff --git a/examples/devkits/Eurorack-DevKit-Template/Makefile b/examples/devkits/Eurorack-DevKit-Template/Makefile index 6650d16c5..574b90f62 100644 --- a/examples/devkits/Eurorack-DevKit-Template/Makefile +++ b/examples/devkits/Eurorack-DevKit-Template/Makefile @@ -8,22 +8,18 @@ TARGET = Eurorack-DevKit-Template DEBUG = 1 OPT = -Og -# Use bootloader? -#APP_TYPE=BOOT_SRAM +# (optional) Use bootloader +# APP_TYPE=BOOT_SRAM # Sources CPP_SOURCES = src/main.cpp -#CPP_STANDARD=-std=gnu++17 - LIBDAISY_DIR = ../../../ # (optional) Add DaisySP # DAISYSP_DIR = ../../DaisySP # USE_DAISYSP_LGPL=1 -# C_INCLUDES += -I../include/ -I./include/ - # (optional) Includes FatFS source files within project. USE_FATFS = 1 diff --git a/examples/devkits/Pedal-DevKit-Template/Makefile b/examples/devkits/Pedal-DevKit-Template/Makefile index a955bbea3..ff9b8a463 100644 --- a/examples/devkits/Pedal-DevKit-Template/Makefile +++ b/examples/devkits/Pedal-DevKit-Template/Makefile @@ -11,8 +11,6 @@ OPT = -Og #(optional) use the bootloader # APP_TYPE=BOOT_SRAM -# CPP_STANDARD= -std=gnu++17 - # Sources CPP_SOURCES = src/main.cpp From adf29a5f1ccbb7096efaf1579faa3dfc58003da7 Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Thu, 24 Sep 2026 09:50:36 -0700 Subject: [PATCH 11/12] corrected type mismatch on desktop devkit loops over component qty consts --- src/desktop_devkit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/desktop_devkit.cpp b/src/desktop_devkit.cpp index 839b25a75..951499332 100644 --- a/src/desktop_devkit.cpp +++ b/src/desktop_devkit.cpp @@ -62,9 +62,9 @@ void Hardware::Init() adc_cfg[2].InitSingle(daisy::seed::D21, conversion_speed); seed.adc.Init(adc_cfg, 3); - for(int i = 0; i < kNumPots; i++) + for(size_t i = 0; i < kNumPots; i++) pot[i].Init(seed.adc.GetMuxPtr(0, i), 1000.f); - for(int i = 0; i < kNumCVs; i++) + for(size_t i = 0; i < kNumCVs; i++) cv[i].InitBipolarCv(seed.adc.GetPtr(i + 1), 1000.f); /** Leds */ @@ -95,7 +95,7 @@ void Hardware::Init() void Hardware::UpdateAllControls() { button_sr.Update(); - for(int i = 0; i < kNumButtons; i++) + for(size_t i = 0; i < kNumButtons; i++) { int sr_idx = 15 - i; button[i].Debounce(button_sr.State(sr_idx)); From a689b8be2b2700f99170f704d585732e1f0d413a Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Thu, 24 Sep 2026 10:00:29 -0700 Subject: [PATCH 12/12] DigitalControl: fixed includes, and put inside daisy namespace. --- src/hid/digital_control.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/hid/digital_control.h b/src/hid/digital_control.h index a443bee1e..5eb55cf49 100644 --- a/src/hid/digital_control.h +++ b/src/hid/digital_control.h @@ -1,6 +1,8 @@ #pragma once -#include "daisy.h" +#include "sys/system.h" +namespace daisy +{ /** Debouncer for non-GPIO switch inputs independent of their source. * For getting `Switch` like behavior from inputs connected to shiftregisters, * etc. @@ -35,7 +37,7 @@ struct DigitalControl state_ = (state_ << 1) | in_val; if(RisingEdge()) { - rising_edge_time_ = daisy::System::GetNow(); + rising_edge_time_ = System::GetNow(); } } @@ -45,6 +47,8 @@ struct DigitalControl inline uint32_t TimeHeldMs() const { - return Pressed() ? daisy::System::GetNow() - rising_edge_time_ : 0; + return Pressed() ? System::GetNow() - rising_edge_time_ : 0; } -}; \ No newline at end of file +}; + +} // namespace daisy \ No newline at end of file