Introduction

 

Welcome the DreamMaker FX! This is an audio platform that makes it very easy to create powerful and unique instrument effects.

It is designed to be accesible for experienced programmers and those who have done no programming.

At its core, this platform is a microprocessor that connects to a powerful SHARC DSP. We program the microprocessor using Arduino tools making it very easy.

Beyond audio processing, the DreamMaker FX hardware offers lots of options for expanding the hardware. External sensors can be easily wired and connected to various effect parameters. The DreamMaker FX hardware also features an RF transceiver meaning that it can communicate wireless with other DreamMaker FX units (or wireless sensors) and exchange various types of parameter information.

How does this thing work?

Okay, here it is: you write simple code (or copy and paste it from the web) into a simple, free programming tool (Arduino). And then a bunch of magic happens and suddenly you’re playing through the coolest effect you’ve ever heard.

 

In this case, the magic is a super powerful SHARC DSP chip that is a friendly companion of the little chip that runs our programs. Unlike other Arduino based effects platforms, this one uses a DSP complete with FFT accelerators and other hardware that gives you at least an order (maybe two) of magnitude in processing performance over other Arduino-based effects platforms. The DSP is where all of the audio processing is done. But you don’t need to know anything about that. Just believe in magic.

Programming? Is this going to hurt?

It’s going to be great. Don’t be a baby. Do you know how to type? Do you know how to follow basic examples? Have you ever copied and pasted on a computer before? You’re going to be amazing.

Programming? It’s 2020, isn’t there an easier way?

Programming allows us to do some cooler stuff that gets a bit tricky with some of the more graphical approaches out there. And we’re programming Arduino-style. Yes, that’s a thing. Are you ready? Yes you are. Do not be afraid. You are going to be great.

What is that word, Arduino?

Have you heard about Arduino? If not, Arduino is this little circuit board created about 10 years ago which was designed to make programming hardware easy. I won’t bore you with the details but that shit got huge. Now lots of people make Arduino-compatible boards (that use their simple programming software) and accessory boards with sensors and other batshit crazy stuff.

So rather than learning some arcane programming language and software tools, you’re using one of the easiest programming tools ever created. And there are plenty of resources for learning and getting help out there. Here’s a great set of tutorials to get started if you’re new to Arduino in general:

https://www.arduino.cc/en/Tutorial/HomePage?from=Main.Tutorials

Okay, so buckle in and get ready to blow some minds.

Installing the tools and hardware

 
Installing the Arduino tools

The DreamMaker FX hardware currently supports Windows 10, OS X, and probably Linux. If you’re running Windows 7, there are a few additional steps that are required to get the UF2 USB device drivers installed.

First order of business, let’s go download some free software and get rolling.

  • Install the Arduino IDE: https://www.arduino.cc/en/main/software and open up the Arduino application.  If you're running OS X Catalina, make sure you're using Arduino v1.8.10 or later.

  • Navigate to either File->Preferences on a PC, or Arduino->Preferences on a Mac. This will open the preferences pane. Towards the bottom, there is a text field called Additional Boards Manager URLs. Add the following to this text box https://runjumplabs.github.io/arduino-board-index/package_dreammaker_fx_index.json. Click okay to close the preferences window.

  • Open up the Arduino board manager from Tools->Board->Board Manager…

  • Scroll down and you should see a link to DreamMaker FX by Run Jump Labs. Click Install!

  • You are now ready to rock!

The setup process is very similar to Adafruit boards which use the same Arduino processor (Atmel SAMD51 family).

This page may offer some additional help https://learn.adafruit.com/adafruit-metro-m4-express-featuring-atsamd51/setup.

Getting the Hardware Connected

The DreamMaker FX hardware is not USB powered so you’ll need to plug it into the wall using the included DC power supply.

Plug the DreamMaker FX hardware into the USB port on your computer. Make sure the USB cable you are using is not a charging cable. There are lots of microUSB charging cables out there that just have wires for power and ground and no data!

You should see a new drive show on your machine called DM_FX. If the DreamMaker FX hardware doesn’t show up when you plug it into your PC or Mac, press the reset button twice in quick succession. The little LED near the USB jack should fade in and fade out rapidly.

In Arduino IDE, go to Tools->Board. You should see lots of options. At the end of the list, you should see DreamMaker FX (SAMD51/ARM Cortex M4 Core). Select this and you’re ready to download effects!

Last thing and this is important: due to a massive brain fart, the input and output guitar jacks are actually backwards :/ The guitar plugs in next to the brass antenna connector hanging off the back of the board. And the amp plugs into the other side (P2).

Before you upload a new effect from the Arduino application, quickly press the reset button twice. This puts it back into bootloader mode. If you don’t do this, you may find that subsequent program downloads fail.

There are four other LEDs on the hardware that dance around together once the DSP is running. If you download an effect and these stop dancing, something has gone catastrophically wrong. Let me (Dan) know if this happens!

Creating a basic echo / delay effect

Effects and synth code is coded in the Arduino IDE and coded in the C++ programming language. However, one doesn’t have to be a programmer to use this platform. The coding patterns for creating various effect and synth components, wiring them together and controlling their parameters is straight forward.

 
Basic Arduino anatomy

With the Arduino app open, go to File->New. You’ll see a new text editor window appear with a new “sketch” (aka a program in Arduino-speak). This sketch will come pre-populated with two functions. One is called setup() and another is called loop().

 

When the sketch is downloaded to our hardware, it will run any commands in the setup() function first. And then it will run the loop() function indefinitely.

void setup() {

   // put your setup code here, to run once:

}

void loop() {

   // put your main code here, to run repeatedly:

 

}

So when creating effects, we will define how the effects connect together in the setup() function and we will then (optionally) adjust the parameters for these effects in the loop() routine.

Let’s start by creating a simple echo effect to see how the pieces fit together.

Step 1: Add the include file for dmfx

At the top of the file, we’ll add a line that will link in all of the functions, variables and objects that you’ll use to create your effects. At the very top of the file, add #include <dmfx.h>. You’ll add this line to the top of every Arduino sketch you create for this platform.

// Include DreamMaker FX library of effects routines

#include "dm_fx.h"

Step 2: Add / "declare" the modules we'll use in the effect

Above the setup routine, we will add (aka declare) any effect and synth objects that we’ll be using. When we add an object, in many cases we will also provide the initial parameters.

In this case, we are going to create a single echo / delay effect object and name it my_echo_1.

 

When we initialize an echo object, it takes two arguments or initial parameters. The first is how long the echo is in milliseconds (1000th of a second). And the second is the feedback ratio (between 0.0 and 1.0) which determines how much audio is fed back into the echo and thus how long the echo lasts. If feedback is set to 1.0, it will echo forever. And if feedback is set to 0.0, it won’t echo at all. Let’s set the echo length to be 1 second (or 1000 milliseconds) and the feedback ratio at 0.7.

Add the following code after your #include "dm_fx.h" line.

// Create/declare one echo effect and configure it

fx_delay my_echo_1(1000.0,      // 1 second echo

                   0.7);        // 0.7 feedback ratio

Step 3: Route the effect into our pedal

Next, in the setup()routine, we need to initialize our effects pedal and route the audio from the pedal in and out jacks through the various effects and synth objects we’re using.

void setup() {

   pedal.init(); // Initialize the system

   // Connect our effect(s) to input and output jacks

   pedal.route_audio(pedal.instr_in, my_echo_1.input); // Instr in -> echo in

   pedal.route_audio(my_echo_1.output, pedal.amp_out); // Echo out -> Amp out

 

   pedal.run(); // Run the effect

 

}

Let’s deconstruct what we just did here.

First, we called the pedal.init() function to set up our system.

Next, we connected the audio from the input jack of our pedal (aka instr_in) to the input of our echo object (aka my_echo_1.input) using the route_audio() function.

Each effect and synthesis object has a set of input and outputs that can “routed” or virtually “wired” together. There are also some inputs and outputs that are part of the pedal itself. Presently, there is an instr_in input (audio in from our instrument) and amp_out output (audio out towards our amp).

In this case, we just have one object. We routed / wired the instr_in to the input of our my_echo_1 object. And then we routed / wired the output of our my_echo_1 object to the pedal output.

And finally, we call pedal.run() which takes our effect configuration, performs the magic, sends it over to the DSP where the effects are run.

Step 4: Add service function to our loop

The last thing we need to do is add the pedal.service(); function call in our loop() function. This function basically checks in the with the DSP, updates any parameters that need to be updated, and retrieves information from the DSP.

void loop() {

   // Sweet nothings to / from the DSP

   pedal.service();

 

}

Bringing it all together

Let’s now look at the whole echo effect.  We just built a delay pedal!  

// Include our library of effects routines

#include "dm_fx.h"

// Create/declare one echo effect and configure it

fx_delay my_echo_1(1000.0,  // 1 second echo

                   0.7);    // 0.7 feedback ratio

 

void setup() {

 

   pedal.init(); // Initialize the system

 

   // Connect our effect(s) to input and output jacks

   pedal.route_audio(pedal.instr_in, my_echo_1.input); // Instr in -> echo in

   pedal.route_audio(my_echo_1.output, pedal.amp_out); // Echo out -> Amp out

 

   pedal.run(); // Run the effect

 

}

 

void loop() {

 

  // put your main code here, to run repeatedly:

 

  // sweet nothings to/from DSP

  pedal.service();

 

}

Running the effect on hardware

As discussed in the installation section, be sure the LED near the USB jack is fading in / fading out. This means the platform is in bootloader mode and is ready to accept a new effect. If the LED is not doing this, press the reset button twice in quick succession.

Click the Upload button in the upper-left hand side of the Arduino IDE (it’s the arrow pointing to the right). Your code will compile and then download to the board. After a second or two, you’ll hear the echo effect applied to any audio you send through the pedal!

Once you have downloaded an effect, it is stored in memory on the pedal. If you disconnect the pedal and plug it in later, it will start up running the same effect. To overwrite the effect currently stored in the pedal, just press the reset button twice in quick success to upload a new effect.

Navigate to Tools -> Serial Monitor. This will bring up the console log. When your effect configuration is processed on the Arduino processor, some information will be sent to the console letting you know how things were routed and everything is okay. You’ll also see the telemetry data from the DSP too so you can see if any effect failed to initialize or something went wrong.

The basics of creating / adding effects

 

As you hopefully remember from 12 seconds ago, we create/declare the effects we want to use at the top of program.

// Create/declare one echo effect and configure it

fx_delay my_echo_1(1000.0,  // 1 second echo

                   0.7);    // 0.7 feedback ratio

The first word (which in this case is fx_delay) is the type of effect we want to create. The API docs contain the complete list of the effects that are available.

We then provide a name for our effect object (which in the example above is my_echo_1). This needs to be a unique word with no spaces (just letters, numbers and underscores really).

And finally, we provide the initial parameters for that effect (i.e. where the knobs are set initially).

Again, the The API docs contain more details on this.

What’s neat is that this object then becomes its own stand-alone effect. We can create multiple objects of the same type in our program (i.e. multiple delays in this case) that each have their own parameters and which are each wired-in in their own ways.

 

// Create/declare two echo effects and configure them

fx_delay my_echo_1(1000.0, 0.7)

fx_delay my_echo_2(2000.0, 0.7);   // Totally legit!

                       

Just make sure each object you create/declare in your system has a unique name even if they are different effect types. For example, don’t do this:

 

// Create/declare two echo effects and configure them

fx_delay       funky_town(1000.0, 0.7)

fx_pitch_shift funky_town(2000.0, 0.7); // BAD! We can't have two effects with same name

                       

Oh yeah, this is important: in some cases an effect will have a few different ways you can initialize it. Most effects have a simple initializer that you just need to pass one or two values to it. And, they may have a more advanced initializer that allows you to do ever more things with that effect. Usually the advanced initializer is a super-set of the simple initializer.

 

// Basic "constructor"

fx_amplitude_mod tremelo_1(1.0// Rate is 1Hz

                           0.5); // Depth is 0.5 (0->1)

// Advanced "constructor"

fx_amplitude_mod tremelo_2(1.0, // Rate is 1Hz

                           0.5, // Depth is 0.5 (0->1)

                           OSC_TRI, // Modulation waveform is triangle instead of sine

                           false); // Not using an external signal as our modulator

The beauty of this is that we have a DSP platform with tons of memory and lots of DSP processing power so you can create effects that incorporate several different individual effect objects / instances.

Routing audio through effects

 

Get ready because we’re going to start using the word node a lot. I hope that’s okay. A node is what it sounds like: it’s a node. Or a point of connection.

Effect audio nodes

Each effect has one or more nodes that can pipe audio into it or out of it. All effects that process audio have both an input node and an output node. Things like an envelope tracker that are just measuring an audio signal may just have an audio input node but no audio output node. Also, some effects have additional nodes beyond input and output and this is where things gets real. Did you see the movie Inception? That question will make sense eventually.

Details on the nodes that each effect has can be found in the API docs.

System audio nodes

And the system has nodes for input from instrument and output to amp.

  • pedal.instr_in is the input jack of the pedal. This might blow your mind, but this is actually an output jack in the sense that it is outputting audio that we can send to the inputs of other effects.

  • pedal.amp_out is the output hack of the pedal. This might blow your mind again, but this is actually an input jack in the sense that it is receiving audio from other effects (and then sending to the amp).

Connecting audio nodes

As we just saw in the echo example, there is a function called route_audio that we use to connect our effects to the input and output jacks of the pedal and also to each other. The first argument of this function is an output node and the second argument is an input node.

Let’s use it in a (programming) sentence. In this example, we’re going to have a tremelo that then feeds into a delay. It’ll be like having your guitar plugged into a tremelo pedal that then plugs into a delay pedal that then plugs into your amp.

(note: if it’s not yet obvious, you can call each effect you create just about whatever you want).

// Create objects for these effects

fx_amplitude_mod happy_tremelo(1.0, 0.5); // 1Hz rate, 0.5 depth

fx_delay sweet_baby_echo(1000.0, 0.7);    // 1000ms, 0.7 feedback

 

void setup() {

  pedal.init(); // Initialize the system

  // Route tremelo through echo/delay effect

  pedal.route_audio(pedal.instr_in, happy_tremelo.input);     

  pedal.route_audio(happy_tremelo.output, sweet_baby_echo.input);   

  pedal.route_audio(sweet_baby_echo.output, pedal.amp_out);

  pedal.run(); // Run the effect

}

Or let’s get more crazy. Let’s say we have a delay pedal and each time through the delay, we’re going to pitch shift up. So it would sound like this: ECHO Echo echo echo (where each time you say ‘echo’ you say it in a lower pitch voice).

The fx_delay has two additional nodes called fx_send and fx_receive. We’re going to run these through our handy-dandy pitch shifter. For this, we’re going to use the more advanced delay setup function / constructor that allows us to pass a few additional parameters.

// Create objects for these effects

fx_delay echoey_snail(1000.0,    // Delay length: 1000ms

                      1000.0,    // Max delay length: 1000ms

                      0.7,       // Feedback: 0.7

                      1.0,       // Clean mix: 1.0

                      true);     // Enable delay fx loop

fx_pitch_shift shift_down(0.85); // Pitch shift down 0.85 x current pitch

 

void setup() {

 

   pedal.init(); // Initialize the system

   // input -> delay -> output

   pedal.route_audio(pedal.instr_in, echoey_snail.input);

   pedal.route_audio(echoey_snail.output, pedal.amp_out);

   // Now patch in pitch shifter into delay fx loop

   pedal.route_audio(echoey_snail.fx_send, shift_down.input);

   pedal.route_audio(shift_down.output, echoey_snail.fx_receive);

   pedal.run(); // Run the effect
 

}

Pretty cool, right?

A few routing rules

Obey these rules to avoid humiliation and sadness:

  1. An output node can be routed to multiple input nodes

    pedal.route_audio(pedal.instr_in, delay_1.input);
    pedal.route_audio(pedal.instr_in, delay_2.input);
     

  2. An input node can only have one input. However, you can use the fx_mixer nodes if you want to send multiple outputs to an input.

    pedal.route_audio(delay_1.output, my_mixer_2.input_1);
    pedal.route_audio(delay_2.output, my_mixer_2.input_2);
    pedal.route_audio(my_mixer_2, pedal.amp_out);

     

  3. And you can’t route input nodes to other input nodes, or output nodes to other output nodes. It’s always output->input.

Controlling effects

 

We’ve been talking a lot about getting effects set up and running. Now let’s talk about how to change the proverbial knobs on the effects once they’re running.

Now, take a deep breath and get comfortable because this next sentence is important. There are two ways we can control effects:

  1. we can use other effects that generate control signals (like the envelope tracker) to control the parameters of other effects or…

  2. we can control the parameters directly from our Arduino program.

Option 1: Using effect control nodes

Similar to our audio nodes, all effects have several control nodes that are inputs for controlling their individual parameters (like delay length and feedback). Some effects have control node outputs like the envelop filter which are control signals based on the audio going through these effects.

Remember when you read “an envelope tracker is just measuring an audio signal and may just have an audio input node but no audio output node”? Well, the envelop tracker has an audio input node and a control output node. Similarly, a synth have a control input node (like a musical node to play) but have an audio output node where the synthesized audio is sent.

We can route these control signals just like we do audio signals using the route_control() function.

For example, let’s say we wanted to create a sweet envelope filter. Essentially what an envelope filter is a bandpass filter that changes frequency based on how loud you are playing. So what we want to do is take the output of the envelop tracker (which tracks how loud the notes we play are) and send this to the center frequency control parameter of a bandbass filter.

Before we get into building this effect, here’s one important detail about how we use the route_control() function: The route_control() function takes two additional values beyond the input and output node: an offset and a scale factor. Here’s what that means. The envelop tracker will generate a control signal between 0 and 1.0 indicating the current volume of the notes we’re playing. However, we want to sweep our filter from say 600Hz to 1400Hz (typical range of a wah pedal). So we want to scale our signal that goes from 0 to 1 to one that goes from 600 to 1400. So we’ll use an offset of 600.0 and then the signal by 800.0. Here’s the equation to keep in the back of your brain:

output = (input x scale_factor) + offset_factor

So let’s create our envelop filter:

fx_biquad_filter auto_wah_filter(800.0,               // Initial frequency is 800Hz

                                 FILTER_WIDTH_NARROW, // Filter is narrow

                                 BIQUAD_TYPE_BPF);    // Filter type is bandpass

 

fx_envelope_tracker vol_tracker(10,         // 10ms attack

                                1000);      // 1000ms / 1s release

 

void setup() {

   pedal.init();   // Initialize the system

   // input -> filter -> output

   pedal.route_audio(pedal.instr_in, auto_wah_filter.input);

   pedal.route_audio(auto_wah_filter.output, pedal.amp_out);

 

   // Also send audio in to our envelope tracker to measure the signal

   pedal.route_audio(pedal.instr_in, vol_tracker.input);

   // Finally, route the control signals so the envelope tracker can control

   // the filter with scale and offset values

   pedal.route_control(vol_tracker.envelope, auto_wah_filter.freq, 800.0, 600.0);

 

   pedal.run(); // Run the effect

 

}

Option 2: Directly controlling parameters

All effects also include dedicated routines for controlling their parameters. When these routines are called, the effects running on the DSP are immediately updated so these happen in real time.

The loop() function is where we can make these modifications.

Now the question is what value would we use to modify these effects. We happen to have three knobs or “pots” as they’re known (short for potentiometer which is a variable resistor). In our loop function, we can check if these knobs have changed and updated parameters accordingly.

Let’s return to our delay effect. We want our first knob (aka pot0) to control the length of the delay and the second knob to control the feedback. The pot values vary from 0.0 (all the way left) to 1.0 (all the way right).

// Include our library of effects routines

#include <dmfx.h> 

 

// Create/declare one echo effect and configure it

fx_delay my_echo_1(1000.0,   // 1 second echo

                   0.7);     // 0.7 feedback ratio

 

 

void setup() {

   pedal.init(); // Initialize the system

   // Connect our effect(s) to input and output jacks

   pedal.route_audio(pedal.instr_in, my_echo_1.input);

   pedal.route_audio(my_echo_1.output, pedal.amp_out);

 

   pedal.run(); // Run the effect

 

}

 

void loop() {

 

   // put your main code here, to run repeatedly:

   // Control delay length with pot0

   if (pedal.pot0.has_changed()) {

      my_echo_1.set_length_ms(pedal.pot0.val * 1000.0);

   }

 

   // Control delay feedback with pot1

   if (pedal.pot1.has_changed()) {

      my_echo_1.set_length_ms(pedal.pot1.val);

    }

 

   // sweet nothings to/from DSP

   pedal.service();

 

}

Option 3: Controlling effects with external sensors

Where things get really cool is when we begin using sensors and other sources outside the pedal to set parameters. We could use a motion sensor to control a parameter like so.

void loop() {

   // Control echo length using a connected motion sensor:

   my_echo_1.set_length_ms(motion_sensor_position);

   // sweet nothings to/from DSP

   pedal.service();

 

}

 

Debugging Sketches

There are a few different resources that are available for debugging a sketch that isn't working as intended.

When initializing a sketch, you can enable debug by calling pedal.init(true) instead of pedal.init().  This will put the pedal in
"debug mode" which means it will send information to the Serial Monitor (Tools->Serial Monitor).  Open the Serial Monitor before downloading your sketch.  Once the sketch is running, you'll see status info and any errors that were encountered while processing the routing information.

// Include our library of effects routines

#include <dmfx.h> 

 

// Create/declare one echo effect and configure it

fx_delay my_echo_1(1000.0,   // 1 second echo

                   0.7);     // 0.7 feedback ratio

 

 

void setup() {

   pedal.init(true); // Initialize the system

   // Connect our effect(s) to input and output jacks

   pedal.route_audio(pedal.instr_in, my_echo_1.input);

   pedal.route_audio(my_echo_1.output, pedal.amp_out);

 

   pedal.run(); // Run the effect

 

}

You can also generate a report of the final routing and parameters by adding a few additional commands before calling pedal.run().  print_instance_stack() will show you all of the instances in the sketch.  print_routing_table() will show you how the audio and control are wired up.  And print_param_tables will show you the parameters for each instance.

// Include our library of effects routines

#include <dmfx.h> 

 

// Create/declare one echo effect and configure it

fx_delay my_echo_1(1000.0,   // 1 second echo

                   0.7);     // 0.7 feedback ratio

 

 

void setup() {

   pedal.init(true); // Initialize the system

   // Connect our effect(s) to input and output jacks

   pedal.route_audio(pedal.instr_in, my_echo_1.input);

   pedal.route_audio(my_echo_1.output, pedal.amp_out)

 

   pedal.print_instance_stack();
   pedal.print_routing_table();
   pedal.print_param_tables();

   pedal.run(); // Run the effect

 

}

Updating Arduino and DSP firmware

 

To stay current with the latest features and bug-fixes, it's good to keep your system updated!

To do this, we need to

 1. Update the Arduino package 

 2. Update the firmware running on the DSP

Good news, the process is pretty simple!

Step 1: Update Arduino board package

1. Open up the Board Manager in the Arduino IDE (Tools->Board:..->Board Manager).

2. Search for Dreammaker FX

3. Select the latest version and click the "Install" button

Step 2: Update DSP Firmware

1. Navigate to your profile icon on this site and in the pull-down select DSP Firmware

2. Download the latest firmware (you'll be redirected to a Dropbox page where you can download the zip file).

3. Open up the ZIP file on your computer

4. If the drive/volume DM_FX isn't showing up on your computer, put the pedal into bootloader mode.

5. Drag CURRENT.UF2 to DM_FX drive/volume

6. Watch the LED dance

7. When complete, put the pedal back in bootloader mode and you're ready to go!

Troubleshooting

 
Error while downloading an Arduino sketch

When clicking the download button, sometimes the download process will stop.  When this happens, wait for the Arduino IDE to display the message "SAM-BA operation failed" which usually happens a few seconds after the download process stops.  Then, put the pedal into bootloader mode.  You should see the DM_FX drive/volume appear on your computer after you do this.  You should now be able to download without issue.

In rare circumstances, the pedal may not respond to the bootloader sequence.  In this case, remove the back cover of the pedal and press the reset button on the circuit board twice in quick succession.  A small LED near the USB connector should flash a few times and then slowly strobe in and out (like it is breathing).   This will also put the pedal into bootloader mode.  You should see the DM_FX drive/volume appear on your computer after you do this.  You should now be able to download without issue.

After downloading my sketch, one LED is on and the other is strobing

If the pedal encounters an error while downloading your sketch, it will turn on the left LED and periodically strobe the right LED.  The number of times the right LED strobes in quick succession indicates the issue the pedal encountered.

   2 flashes - the pedal encountered an illegal routing combination (e.g. two output nodes connected to an input node)

   3 flashes - the firmware running on the DSP does not match the Arduino package version.  

   5 flashes - the DSP is not running or responding.  Run for the hills.

I am getting a "bad CPU type in executable" error when compiling my sketch

Upgrade your Arduino tools to version 1.8.10 or later.  This is a known issue running Arduino on OS X Catalina.

© 2020 DreamMaker FX by Run Jump Labs

  • Twitter - White Circle
  • Instagram - White Circle