One cable going to the ST-Link V2 (and into the computer via USB), the other cable is providing power from my module case. You need both connected to upload firmware.

How to get started writing your own firmware for Mutable Instruments Clouds

What you need to get started: Hardware

  • A Mutable Instruments Clouds Module (I bought mine from Post Modular)
  • A Computer. These instructions assume you’re on a Mac, but you can also use a PC or Linux machine.
  • A Programmer. I use a ST-Link V2, which costs about £60. Émilie Gillet uses a Olimex ARM-USB-OCD-H JTAG, which is about the same price. There are also cheaper ways to do it — you can buy a differently branded ST-Link V2 for £7.99 on Amazon, or some development boards have the hardware built in. These cheaper tools may work, I don’t know. I wanted one less thing to go wrong, so bought the real thing.
  • You also need this Olimex JTAG Adaptor to fit the tiny pins on the back of Mutable Instruments modules. It costs about £8.

Getting started: Installing your environment

  1. Download the Mutable Environment files Follow this link to the GitHub page and click the green ‘Clone or download’ button. Choose ‘Download ZIP’. Open the zip file, and place the folder somewhere safe. I created a ‘MutableEnvironment’ folder inside Documents, with the ‘mutable-dev-environment-master’ folder unchanged within that.
  2. Install the software Follow the links in the Mutable Development Environment GitHub page for VirtualBox, VirtualBox Extension Pack and Vagrant. I found all three installed normally and didn’t need to use the command line for the Extension Pack.
  3. Get a text editor I’ve been using Text Wrangler, which is free and works fine, as will many others.
  4. Open the folder where you left the files in Terminal If you’re as clueless as I was with Terminal, this is how you do it:
    1. Launch Terminal.
    2. Arrange a finder window so you can see the “mutable-dev-environment-master” folder.
    3. In terminal, type “cd” (change directory) and hit the space bar.
    4. Drag the “mutable-dev-environment-master” folder into the terminal window.
    5. Hit return in the Terminal window, and the prompt will show you’re now in the right directory.
    6. Type “ls” and hit return to see a list of the files, just to make sure.
  5. Launch the environment All the details are in the GitHub documentation, but it’s very simple: You type “vagrant up” and the system goes away to build the virtual machine — it takes 15–30 minutes the first time. Don’t get impatient and try to cancel it. Then you type “vagrant ssh” to enter the virtual machine. Now, if you type “ls” you’ll see a list of all the files in the Mutable Instruments GitHub; braids, branches etc.
  6. Check the shared folder If you go back to Finder, and look in mutable-dev-environment-master, you’ll find a folder called “eurorack-modules”. This is the shared folder. Edit the files here, compile and upload them through the virtual machine.
  7. Try it out As the documentation explains, if you type “make -f clouds/bootloader/makefile hex” and hit return, the system should go away and compile the bootloader for Clouds. The files the system creates appear in a folder called “build” inside “‘eurorack-modules”
  8. What if it doesn’t work? Well, I can’t help you there, beyond going back and reading the GitHub documentation again. You can try searching the Mutable Instruments forum with any error codes, or ask to join Facebook groups like “Euro SMD DIY Noobs”.
My jtag cable came unmarked, try it either way around, it doesn’t seem to blow anything up.

Uploading code to the Clouds module

export PGM_INTERFACE=stlink-v2
export PGM_INTERFACE_TYPE=hla
  1. Clouds needs power from your modular case and the STLink USB connection at the same time to receive firmware. I have mine installed in the case, with the STLink dangling round the back and a USB cable coming out into the computer.
  2. The cable with the little Red Olimex adaptor isn’t clearly labelled. For me, the pin marked 1 seems to be connected to the pin marked JTAG on the Clouds module. I tried it both ways round, and nothing blew up (but it didn’t work the other way).
make -f clouds/makefile upload
make -f clouds/makefile upload_combo_jtag

Lets write some code: Hello World for Clouds

void setup() {
pinMode(13, OUTPUT); // The LED is connected to Pin 13
}
void loop() {
digitalWrite(13, HIGH); // turn the LED on
delay(1000); // wait for a second
digitalWrite(13, LOW); // turn the LED off
delay(1000); // wait for a second
}
  • Flickers the LEDs
  • Takes Left input to the Left output, with the volume controlled by the Position control (just like a passive attenuator!)
  • Ring modulates the Left and Right inputs, sending the result to the Right output.

Lets write some code: Making changes

  1. At the top is the license, in comments.
  2. Then there are various setup lines, pulling in external libraries and doing things I don’t yet understand.
  3. One variable (counter) is created that will be used later.
  4. Then you find a function called SysTick_Handler. Anything in this block — as the comments explain — is called every millisecond. Some human interface things — checking knobs, turning LEDs off and on, might happen here. They’re not timing-critical, so don’t need to happen constantly.
  5. Below that is a function called FillBuffer. This is the beating heart of the module. It’s called every 32 samples, or 1,500 times a second, and it’s where the system fills up the buffers for the codec, the chip that takes audio input in and sends audio output out.
  6. Inside FillBuffer is a loop around while (n — ); this is where each individual sample is processed, so it has to run 48,000 times a second.
  7. Below that is Init(), which is run once at the startup of the module, where sample rates etc are set.
  8. Finally at the bottom is main(void), which is the empty main loop that does nothing while timers make all the other routines work.
// a little LED animation for fun 
for(int i=0; i<4; i++) {

Building a simple delay

// create an array with space for one second of audiouint32_t delayLength = 48000;
int16_t delayLine[48000];
// create variables to store record and playback positions
// Use floats for these because we might want to have them
// move faster or slower.
// Start playback one sample *ahead* of the record head, because
// they're going to be in a loop.
double recordHead = 0;
double playHead = 1;
// Write the Left input to the delay line// Using the modulo "% delayLength" means it writes in a loop
// starting again at the beginning when it gets to the end
// Use (long) to convert the float into an integer, you can't
// use a float to set the index on an array
delayLine[(long)recordHead % delayLength] = input->l;
recordHead++;
// Read the Left output from the delay lineoutput->l = delayLine[(long)playHead % delayLength];
playHead++;
This black Clouds panel comes from Magpie Modular.

Things I’ve learned along the way, in no particular order

  • Audio comes in and goes out as 16-bit integers (int16_t); -32,768 to 32,767. Signal processing is normally done as 32-bit floats; where -1 to +1 represents the signal. To convert between the two:
int16_t y = static_cast<int16_t>(x * 32768.0);
float y = static cast<float>(x) / 32768.0;
  • Adding two audio signals together works like mixing. Multiplying them works like amplitude (ring) modulation. In both cases, you’ll need to do some division afterwards, to ensure the output doesn’t clip (there are also other ways to do this.)
  • When you get something ‘wrong’ you’ll hear weird crackling sounds at the outputs — for example if a number is overflowing and producing unexpected results every so often, that happening at 48khz sounds like weird crackling. Sometimes, the weird crackling sounds interesting. Sometimes wrong sounds great.
  • Pots and CV inputs produce zero-to-one floats. That’s why multiplying the input by a pot position works as an attenuator. You can find a list of the available inputs in enum_AdcChannel here.
  • A big difference between this and simple Arduino code is that it is designed to be non-blocking. Arduino code typically does one thing at a time. If you call “delay(1000)” the entire system stops and waits. Emilie’s code for Clouds works differently. If you call “ adc.Convert()” the system goes off to read all the potentiometers and CV inputs, which takes hundreds of microseconds, but it’s still able to do other things (like playing audio) at the same time.
  • As you get more confident, start reading through the rest of the Clouds firmware, to find lots of useful routines and ideas.

Next steps and further reading

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Tom Whitwell

Consultant at Magnetic (formerly Fluxx), reformed journalist, hardware designer.