Skip to content

Commit facb66c

Browse files
Seed3 DevKits (#717)
* add devkit source files, and new DigitalControl (Switch debouncing for non-GPIO objects), included in daisy.h * bump C++ Standard to gnu++17 (previously gnu++14) * resolve vs code intellisense issues with missing USBH middleware/conf * added devkits and C++ standard bump to CMake build. * basic template/example programs for the Eurorack and Pedal devkits. * Desktop DevKit UI Template example, and minor tweaks to desktop devkit Hardware class. * fixed devkit styling issues * reverted back to C++14, and moved inline constexpr to be namespace level constexpr for each devkit. * added consts for component quantities (kNumPots, kNumButtons, etc.) to desktop devkit to match other boards. * cleanup new example Makefiles. * corrected type mismatch on desktop devkit loops over component qty consts * DigitalControl: fixed includes, and put inside daisy namespace.
1 parent 265aae3 commit facb66c

21 files changed

Lines changed: 1396 additions & 2 deletions

File tree

‎.vscode/c_cpp_properties.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,16 @@
88
"${workspaceRoot}/tests/googletest/googletest/include",
99
"${workspaceRoot}/src/sys",
1010
"${workspaceRoot}/src/usbd",
11+
"${workspaceRoot}/src/usbh",
1112
"${workspaceRoot}/Drivers/CMSIS_5/CMSIS/Core/Include",
1213
"${workspaceRoot}/Drivers/CMSIS-Device/ST/STM32H7xx/Include",
1314
"${workspaceRoot}/Drivers/STM32H7xx_HAL_Driver/Inc",
1415
"${workspaceRoot}/Drivers/STM32H7xx_HAL_Driver/Inc/Legacy",
1516
"${workspaceRoot}/Middlewares/ST/STM32_USB_Device_Library/Core/Inc",
1617
"${workspaceRoot}/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc",
18+
"${workspaceRoot}/Middlewares/ST/STM32_USB_Host_Library/Core/Inc",
19+
"${workspaceRoot}/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc",
20+
"${workspaceRoot}/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc",
1721
"${workspaceRoot}/Middlewares/Third_Party/FatFs/src"
1822
],
1923
"defines": [

‎CMakeLists.txt‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ add_library(daisy STATIC
4848
${MODULE_DIR}/daisy_pod.cpp
4949
${MODULE_DIR}/daisy_seed.cpp
5050
${MODULE_DIR}/daisy_versio.cpp
51+
${MODULE_DIR}/desktop_devkit.cpp
52+
${MODULE_DIR}/eurorack_devkit.cpp
53+
${MODULE_DIR}/pedal_devkit.cpp
5154
${MODULE_DIR}/dev/codec_ak4556.cpp
5255
${MODULE_DIR}/dev/codec_pcm3060.cpp
5356
${MODULE_DIR}/dev/codec_wm8731.cpp
@@ -130,15 +133,13 @@ target_compile_options(daisy PRIVATE
130133
$<$<CXX_COMPILER_ID:GNU>:-Wno-missing-attributes>
131134
)
132135

133-
134136
set_target_properties(daisy PROPERTIES
135137
CXX_STANDARD 14
136138
CXX_STANDARD_REQUIRED
137139
C_STANDARD 11
138140
C_STANDARD_REQUIRED
139141
)
140142

141-
142143
# Don't add examples if we're being included in another project
143144
if(PROJECT_IS_TOP_LEVEL)
144145
add_subdirectory(examples EXCLUDE_FROM_ALL)

‎Makefile‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ daisy_field \
2828
daisy_versio \
2929
daisy_legio \
3030
daisy_patch_sm \
31+
desktop_devkit \
32+
eurorack_devkit \
33+
pedal_devkit \
3134
sys/fatfs \
3235
sys/system \
3336
dev/sr_595 \
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Project Name
2+
TARGET = Desktop-DevKit-UI-Template
3+
4+
# Configure for debugging
5+
# common configurations:
6+
# use DEBUG = 1 and OPT = -Og for debugging
7+
# or DEBUG = 0 and OPT = -O3 for performance
8+
DEBUG = 1
9+
OPT = -Og
10+
11+
# (optional) use bootloader
12+
APP_TYPE=BOOT_SRAM
13+
14+
# Sources
15+
CPP_SOURCES = src/main.cpp
16+
17+
LIBDAISY_DIR = ../../../
18+
19+
# (optional) Add DaisySP
20+
# DAISYSP_DIR = ../path/to/DaisySP
21+
# USE_DAISYSP_LGPL=1
22+
23+
# (optional) Includes FatFS source files within project.
24+
USE_FATFS = 1
25+
26+
# Core location, and generic Makefile.
27+
SYSTEM_FILES_DIR = $(LIBDAISY_DIR)/core
28+
29+
# Use the bootloader variant that allows programming DFU over the
30+
# external USB port (used to power the devkit).
31+
BOOT_BIN=$(SYSTEM_FILES_DIR)/dsy_bootloader_v6_4-extdfu-2000ms.bin
32+
33+
include $(SYSTEM_FILES_DIR)/Makefile
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Desktop Devkit UI Template
2+
3+
This example is a bit more complex than the other examples in the repo.
4+
5+
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.
6+
7+
The 16 buttons, 8 pots, and LEDs are all managed using libDaisy's UI class from `main_page.h`.
8+
9+
As usual inputs are read in the AudioCallback. UI Events are then created for the relevant pieces of the interface.
10+
Inside the Low-priority Callback, the events are handled, and the LED UI is redrawn.
11+
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.
12+
13+
## Flashing to the Daisy
14+
15+
This is designed to use the external USB version of the bootloader.
16+
17+
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/).
18+
19+
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).
20+
21+
With the device connected, press RESET and then BOOT on the Seed.
22+
You should see the USR LED on the Daisy blink quickly and then start slowly pulsing.
23+
24+
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.
25+
26+
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.
27+
28+
## Connecting to the Program
29+
30+
Once the program has been flashed to the Daisy, you'll see that the Seed's USR LED is blinking at a steady rate.
31+
You can push each of the tactile switches to see the corresponding LED illuminate.
32+
33+
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.
34+
35+
You can connect to the program using a serial monitor, and see print statements that occur whenever any input is changed.
36+
37+
Within the source code you'll see that many of these print statements are set within on change callbacks in the `main_page.h`.
38+
Other inputs are checked in the Audio Callback, and messages are generated to be sent from the main `while()` loop.
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
/** Desktop DevKit UI Template
2+
*
3+
* UI template program for the Desktop DevKit
4+
*
5+
* This program uses the libDaisy UI framework to generate events from the input
6+
* that can be handled within UI pages.
7+
* This is a bit more complex than the simpler approach to handling UI in other examples,
8+
* but provides a lot of flexibility for more involved applications.
9+
*
10+
* Since the Desktop DevKit is USB powered via the port on the devkit, this build uses the
11+
* external variant of the bootloader so that the seed on the devkit can be reprogrammed
12+
* while connected to the single USB port on the desktop devkit.
13+
*
14+
* This program:
15+
* - initializes the Desktop DevKit hardware
16+
* - starts an audio callback to do pass through, update the controls, and generate UI events
17+
* - starts a low-priority callback to process the UI events
18+
* - prints input data from the `main_page.h` event hooks over USB serial
19+
*/
20+
#include "desktop_devkit.h"
21+
#include "userinterface.h"
22+
23+
using namespace daisy;
24+
using namespace daisy::desktop_devkit;
25+
26+
/** Naive hysteresis filter for printing CV input changes
27+
*
28+
* Only update the value if the input has changed by enough to print.
29+
*/
30+
struct CvChangeFilter
31+
{
32+
float prev_val;
33+
bool changed;
34+
35+
/** simple constructor */
36+
CvChangeFilter() : prev_val(0.f), changed(false) {}
37+
38+
/** compares the input to the last value output, and updates it if it exceeds a threshold of 0.1 */
39+
inline float Process(const float in)
40+
{
41+
changed = false;
42+
if(std::abs(in - prev_val) > 0.01f)
43+
{
44+
prev_val = in;
45+
changed = true;
46+
}
47+
return prev_val;
48+
}
49+
50+
/** returns true the value changed last time `Process` was called */
51+
inline bool Changed() const { return changed; }
52+
};
53+
54+
/** Global Hardware object */
55+
Hardware hw;
56+
57+
/** Global UI object */
58+
Ui ui;
59+
60+
/** FIFO of strings that we can use to move messages from the Audio callback
61+
* to be printed in the main while() loop.
62+
*/
63+
FIFO<FixedCapStr<32>, 16> msg_fifo;
64+
65+
/** state of 3-way toggle for output when changed */
66+
int prev_toggle_pos = 0;
67+
68+
/** Simple filters for CV inputs to only output values when they have changed */
69+
CvChangeFilter cv_change_filt[2];
70+
71+
void AudioCallback(AudioHandle::InputBuffer in,
72+
AudioHandle::OutputBuffer out,
73+
size_t size)
74+
{
75+
hw.UpdateAllControls();
76+
ui.GenerateEvents();
77+
78+
// Here we'll send some strings based on events not covered in the UI.
79+
//
80+
// Certain things (e.g. gate inputs, CV inputs, etc.) often make more sense to
81+
// handle within the audio callback so that there is a new value once per callback,
82+
// syncronized with the block of audio it was read in.
83+
//
84+
// A few of these (e.g. toggles) could be handled in the UI pages.
85+
86+
// Gate Inputs
87+
if(hw.gate_in[0].Trig())
88+
msg_fifo.PushBack("Gate In 1: Trig!");
89+
if(hw.gate_in[1].Trig())
90+
msg_fifo.PushBack("Gate In 2: Trig!");
91+
92+
// Input detection changes
93+
if(hw.sd_detect.FallingEdge())
94+
msg_fifo.PushBack("SD card removed");
95+
else if(hw.sd_detect.RisingEdge())
96+
msg_fifo.PushBack("SD card inserted");
97+
98+
if(hw.left_detect.FallingEdge())
99+
msg_fifo.PushBack("Left input removed");
100+
else if(hw.left_detect.RisingEdge())
101+
msg_fifo.PushBack("Left input inserted");
102+
103+
if(hw.right_detect.FallingEdge())
104+
msg_fifo.PushBack("Right input removed");
105+
else if(hw.right_detect.RisingEdge())
106+
msg_fifo.PushBack("Right input inserted");
107+
108+
// 2-way Toggle
109+
if(hw.tog_sw17.FallingEdge())
110+
msg_fifo.PushBack("SW17: Down");
111+
else if(hw.tog_sw17.RisingEdge())
112+
msg_fifo.PushBack("SW17: Up");
113+
114+
// 3-way Toggle
115+
auto new_tog_pos = hw.tog_sw18.Read();
116+
if(prev_toggle_pos != new_tog_pos)
117+
{
118+
switch(new_tog_pos)
119+
{
120+
case Switch3::POS_CENTER: msg_fifo.PushBack("SW18: Center"); break;
121+
case Switch3::POS_UP: msg_fifo.PushBack("SW18: Up"); break;
122+
case Switch3::POS_DOWN: msg_fifo.PushBack("SW18: Down"); break;
123+
default: break;
124+
}
125+
prev_toggle_pos = new_tog_pos;
126+
}
127+
128+
// CV Inputs
129+
auto cv1 = cv_change_filt[0].Process(hw.cv[0].Value());
130+
if(cv_change_filt[0].Changed())
131+
{
132+
FixedCapStr<32> msg("CV1: ");
133+
msg.AppendFloat(cv1);
134+
msg_fifo.PushBack(msg);
135+
}
136+
auto cv2 = cv_change_filt[1].Process(hw.cv[1].Value());
137+
if(cv_change_filt[1].Changed())
138+
{
139+
FixedCapStr<32> msg("CV2: ");
140+
msg.AppendFloat(cv2);
141+
msg_fifo.PushBack(msg);
142+
}
143+
144+
// Audio pass through
145+
for(size_t i = 0; i < size; i++)
146+
{
147+
out[0][i] = in[0][i];
148+
out[1][i] = in[1][i];
149+
}
150+
}
151+
152+
153+
/** This callback happens every 4ms (250Hz) and can be interrupted by
154+
* everything except for the SysTick interrupt.
155+
* The frequency of this callback is set in the `Hardware::StartLowPriorityCallback`
156+
* parameters.
157+
*
158+
* Handling the UI events here means that anything we do in the main while()
159+
* loop that may take an indeterminate time (file system I/O, QSPI Saving, etc.)
160+
* won't cause the UI to stall during those processes
161+
*/
162+
void LowPriorityCallback(void *data)
163+
{
164+
// Handles events, and redraws the current UI pages
165+
ui.DoEvents();
166+
}
167+
168+
int main(void)
169+
{
170+
hw.Init();
171+
System::Delay(50);
172+
Logger<LOGGER_EXTERNAL>::StartLog(false);
173+
ui.Init(&hw);
174+
175+
hw.StartLowPriorityCallback(LowPriorityCallback, 250);
176+
hw.seed.StartAudio(AudioCallback);
177+
178+
auto last_dac_write = System::GetNow();
179+
uint16_t dac_value = 0;
180+
181+
while(true)
182+
{
183+
auto now = System::GetNow();
184+
185+
/** Handle MIDI events */
186+
while(hw.midi.HasEvents())
187+
{
188+
auto msg = hw.midi.PopEvent();
189+
switch(msg.type)
190+
{
191+
case NoteOn:
192+
// Echo note on messages to the MIDI out
193+
{
194+
uint8_t bytes[3] = {0x90, 0x00, 0x00};
195+
bytes[1] = msg.data[0];
196+
bytes[2] = msg.data[1];
197+
hw.midi.SendMessage(bytes, 3);
198+
}
199+
break;
200+
default: break;
201+
}
202+
}
203+
204+
/** Write a ramp (cv out 1) and saw (cv out 2) waveform to the DAC outputs
205+
* Approx. 2.5s period for waveform (0.005s * (4096 / 8)) = 2.56s
206+
*/
207+
if(now - last_dac_write > 5)
208+
{
209+
dac_value += 8;
210+
if(dac_value > 4095)
211+
{
212+
dac_value = 0;
213+
}
214+
hw.SetDacOut(DacHandle::Channel::ONE, dac_value);
215+
hw.SetDacOut(DacHandle::Channel::TWO, 4095 - dac_value);
216+
last_dac_write = now;
217+
}
218+
219+
/** Print messages from the audio callback */
220+
while(!msg_fifo.IsEmpty())
221+
{
222+
auto msg = msg_fifo.PopFront();
223+
Logger<LOGGER_EXTERNAL>::PrintLine(msg.Cstr());
224+
}
225+
226+
System::Delay(1);
227+
}
228+
229+
return 0;
230+
}

0 commit comments

Comments
 (0)