Custom Code in Arduino

If you want to customize the Trellis M4 Expressive MIDI Controller beyond the .uf2 firmware you dragged onto the board, we'll need to use Arduino IDE to code it.

First, get set up with Arduino IDE as detailed here.

Next, follow these instructions on getting the proper libraries installed. In this code we use the following libraries:

  • Adafruit_Keypad
  • Adafruit_NeoPixel
  • Adafruit_Sensor
  • Adafruit_ADXL343
  • MIDIUSB

Once you've updated the board definitions as shown, you'll be able to select Adafruit Trellis M4 (SAMD51) as your board for compiling and uploading.

Copy the code shown below and paste it into a new sketch in Arduino. Save the sketch as midi_keypad.ino and then upload it to your board.

Note: if you have any problem uploading to the board, double-click the reset button on the back of the board during the upload to set the Trellis M4 into bootloader mode. The on-board status LED (on the back) will be purple during normal running mode and switch to green when it is in bootloader mode.

// Trellis M4 MIDI Keypad CC
// sends 32 notes, pitch bend & a CC from accelerometer tilt over USB MIDI

#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL343.h>
#include <Adafruit_NeoTrellisM4.h>

#define MIDI_CHANNEL     0  // default channel # is 0
// Set the value of first note, C is a good choice. Lowest C is 0.
// 36 is a good default. 48 is a high range. Set to 24 for a bass machine.
#define FIRST_MIDI_NOTE 36

Adafruit_ADXL343 accel = Adafruit_ADXL343(123, &Wire1);

int xCC = 1;  //choose a CC number to control with x axis tilting of the board. 1 is mod wheel, for example.

int last_xbend = 0;
int last_ybend = 0;

Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4();

void setup(){
  Serial.begin(115200);
  //while (!Serial);
  Serial.println("MIDI keypad & pitchbend!");
    
  trellis.begin();
  trellis.setBrightness(80);

  // USB MIDI messages sent over the micro B USB port
  Serial.println("Enabling MIDI on USB");
  trellis.enableUSBMIDI(true);
  trellis.setUSBMIDIchannel(MIDI_CHANNEL);
  // UART MIDI messages sent over the 4-pin STEMMA connector (3.3V logic)
  Serial.println("Enabling MIDI on UART");
  trellis.enableUARTMIDI(true);
  trellis.setUARTMIDIchannel(MIDI_CHANNEL);
  
  if(!accel.begin()) {
    Serial.println("No accelerometer found");
    while(1);
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  trellis.tick();

  while (trellis.available()){
    keypadEvent e = trellis.read();
    int key = e.bit.KEY;
    Serial.print("Keypad key: ");    Serial.println(key);
    Serial.print("MIDI note: ");     Serial.println(FIRST_MIDI_NOTE+key);

    if (e.bit.EVENT == KEY_JUST_PRESSED) {
      Serial.println(" pressed\n");
      trellis.setPixelColor(key, 0xFFFFFF);
      trellis.noteOn(FIRST_MIDI_NOTE+key, 64);
    }
    else if (e.bit.EVENT == KEY_JUST_RELEASED) {
      Serial.println(" released\n");
      trellis.setPixelColor(key, 0x0);
      trellis.noteOff(FIRST_MIDI_NOTE+key, 64);
    }
  }

  // Check for accelerometer
  sensors_event_t event;
  accel.getEvent(&event);
  /* Display the results (acceleration is measured in m/s^2) */
  //Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print("  ");
  //Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print("  ");
  //Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print("  ");Serial.println("m/s^2 ");
  int xbend = 0;
  int ybend = 0;

  if (abs(event.acceleration.y) < 2.0) {  // 2.0 m/s^2
    // don't make any bend unless they've really started moving it
    ybend = 8192; // 8192 means no bend
  } else {
    if (event.acceleration.y > 0) {
      ybend = ofMap(event.acceleration.y, 2.0, 10.0, 8192, 0, true);  // 2 ~ 10 m/s^2 is downward bend
    } else {
      ybend = ofMap(event.acceleration.y, -2.0, -10.0, 8192, 16383, true);  // -2 ~ -10 m/s^2 is upward bend
    }
  }
  if (ybend != last_ybend) {
    Serial.print("Y pitchbend: "); Serial.println(ybend);
    trellis.pitchBend(ybend);
    last_ybend = ybend;
  }

  if (abs(event.acceleration.x) < 2.0) {  // 2.0 m/s^2
    // don't make any bend unless they've really started moving it
    xbend = 0;
  } else {
    if (event.acceleration.x > 0) {
      xbend = ofMap(event.acceleration.x, 2.0, 10.0, 0, 127, true);  // 2 ~ 10 m/s^2 is upward bend
    } else {
      xbend = ofMap(event.acceleration.x, -2.0, -10.0, 0, 127, true);  // -2 ~ -10 m/s^2 is downward bend
    }
  }
  if (xbend != last_xbend) {
    Serial.print("X mod: "); Serial.println(xbend);
    trellis.controlChange(xCC, xbend);  //xCC is set at top of sketch. e.g., CC 1 is Mod Wheel
    last_xbend = xbend;
  }

  trellis.sendMIDI(); // send any pending MIDI messages

  delay(10);
}



// floating point map
float ofMap(float value, float inputMin, float inputMax, float outputMin, float outputMax, bool clamp) {
    float outVal = ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin);

    if (clamp) {
      if (outputMax < outputMin) {
        if (outVal < outputMax)  outVal = outputMax;
        else if (outVal > outputMin)  outVal = outputMin;
      } else {
        if (outVal > outputMax) outVal = outputMax;
        else if (outVal < outputMin)  outVal = outputMin;
      }
    }
    return outVal;

}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return trellis.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return trellis.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return trellis.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

The most likely things you'll want to change are the MIDI channel, the MIDI note range of the keypad buttons, and the CC channel numbers of the accelerometer tilt axes.

MIDI Channel

You can adjust the MIDI channel by changing the value of this line:

#define MIDI_CHANNEL 0 // default channel # is 0

To change this controller to send MIDI over channel 6, for example, you could make it read:

#define MIDI_CHANNEL 6

Note Range

The Trellis M4's 32 buttons are set up in this project as chromatic keys with the low note set to C3. This corresponds to MIDI notes 36 through 68. You can change this range by adjusting this line in the code:

#define FIRST_MIDI_NOTE 36

CC Channel

The x-axis (forward/backward) tilt of the Trellis M4's accelerometer is set by default to send out a range of 0-127 values over MIDI CC channel 1. This is typically received as "mod wheel" in most synthesizers. You can change this value, in case it isn't simple in your software synth to re-assign which knob is turned by CC 1. This line is the one to adjust:

int xCC = 1;

Once you're done making changes, upload the sketch to your Trellis M4 and test it out in your MIDI monitor utility and synth!

Test MIDI Output

You can test to see that your Trellis M4 is outputting MIDI signals properly by using a MIDI utility. These will report all activity coming from any MIDI controller plugged into your system. Here are some to try:

This guide was first published on Nov 11, 2018. It was last updated on Nov 11, 2018. This page (Custom Code in Arduino) was last updated on Feb 19, 2020.