XIAO SAMD21, Arduino and MIDI – Part 7

This post looks at the possibilities of using I2C peripherals with a Seeedstudio XIAO SAMD21 and the XIAO Expansion Board.  The projects should work with either USB MIDI or serial MIDI via an external MIDI module.

Note: There is just one project described at present, but others will be added to this post as they happen.

Other parts in this series:

  • Part 1 – Introduction to the XIAO SAMD21 and some projects to get started.
  • Part 2 – Looking at accessing additional serial ports and using them for MIDI.
  • Part 3 – Mozzi FM synthesis using the DAC on the XIAO.
  • Part 4 – USB MIDI on the XIAO.
  • Part 5 – XIAO as a USB MIDI Host.
  • Part 6 – MIDI control using the expansion board.
  • Part 7 – XIAO Expansion I2C MIDI control.
  • Part 8 – XIAO MIDI PCBs.

Note: Although I’ve had vouchers from Seeed Studio for their Fusion service to support the manufacturing of some of my PCBs, there is no support for my use of the XIAO boards for this post.  I bought these a while ago, bought my own expansion board more recently, and just wanted a bit of a play to see what I could come up with.

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

These are the key tutorials for the main concepts used in this project:

If you are new to microcontrollers, see the Getting Started pages.

Parts list

  • Seeed Studio XIAO SAMD21.
  • Seeed Studio XIAO Expansion Board.
  • Range of additional components depending on the project (see details below).
  • Grove compatible cables*.
  • Optional: 3V3 compatible MIDI module, for example one of the Ready-Made MIDI Modules or DIY MIDI Interfaces.
  • MDI devices as required to source or sink MIDI.
  • Breadboard and jumper wires.

See part 6 for details of how to connect a MIDI circuit to the XIAO expansion board, and see the notes in part 1 about uploading to the XIAO and what to do if there are issues.

* In some cases, my “Grove compatible cables” seem to be coloured Black-Red-Yellow-White and in some cases they are Black-Red-White-Yellow!  I guess as long as Black and Red are the same, it doesn’t matter quite so much about the Yellow and White!  But it does mean that it isn’t always easy to spot which pin is which, especially when using I2C connectors, as the colours aren’t consistent for SCL/SDA.

M5Stack 8Angle MIDI Step Sequencer

Additional parts required:

Note: These came with cables that are using the following grove cable colour code:

  • Black – GND
  • Red – VCC
  • Yellow – SDA
  • White- SCL

XIAO-Expansion-M5Stack-8Angle_bb

The M5Stack 8Angle is a neat little device that has a built-in microcontroller to read the potentiometers and present their values over I2C to a host.  It also includes a slider switch and 9 RGB LEDs.

Aside – Warning: The M5Stack 8Angle is specified to require a 5V input source on the Grove connector.  The schematic shows that this is regulated down to 3V3 internally using a ME6210A33M3G to run everything else.  But from my experiments, it seems to work ok with the I2C output from the XIAO.  This may be because the MCU used in the unit, the STM32F030F4P6, looks like it has an operating voltage of between 2.4V and 3.6V, and the regulator’s output vs input voltage looks like it might be able to run down to the same voltage as it produces. Also the XIAO expansion board pulls up the I2C lines to 3V3…

But make up your own mind!  Remember my warning – I am not an electronics person!

Full details of how to use it can be found here: https://docs.m5stack.com/en/unit/UNIT 8Angle and there is an Arduino library which can be found here: https://github.com/m5stack/M5Unit-8Angle.  The provided example is designed to work with the M5Stack device itself, so won’t run directly, but here is a short test sketch that will read all 8 potentiometers.

#include <M5_ANGLE8.h>
M5_ANGLE8 angle8;

void setup() {
  Serial.begin(9600);
  while (!angle8.begin(ANGLE8_I2C_ADDR)) {
    Serial.println("angle8 Connect Error");
    delay(100);
  }
}

void loop() {
  if (angle8.getDigitalInput()) {
    for (int i=0; i<ANGLE8_TOTAL_ADC; i++) {
      int aval = angle8.getAnalogInput(i, _12bit);
      Serial.print(aval);
      Serial.print("\t");
    }
    Serial.print("\n");
  }
}

The function getDigitalInput() reads the state of the slider switch on the unit, so it will only run when the switch is “on”.  The pots can be configured for two resolutions – 8-bit or 12-bit.  Here they are configured for 12-bit operation so will return a value in the range 0 to 4095.

The LEDs can be set using the function setLEDColor(led, RGBValue, Brightness).

This application (as shown in the video above) functions as a step sequencer with several configurable options:

  • Four modes of operation: normal and reverse; with and without using the onboard speaker.
  • Mode is changed using the on-board switch on the expander.  Mode is indicated by the number of flashes of the on-board LED.
  • Sends note messages out over serial and USB MIDI.
  • Includes an optional tempo control using a potentiometer on A0.
  • Whole sequence can be muted using the sliding switch,

Here is a summary of the IO used from the XIAO:

  • A0 to the potentiometer (via analog Grove connector).
  • D1 switch in INPUT_PULLUP mode (expander user switch).
  • D3 for speaker (expander built-in speaker).
  • A4/A5 for I2C to the M5Stack 8Angle (via I2C Grove connector).
  • A6/A7 for UART to MIDI (via expander’s additional headers).

All the main configuration options are defined at the top of the code:

#define SPEAKER 3
#define TEMPO_POT A0
#define MODE_SW 1
#define MIDI_CHANNEL 1

With the exception of MIDI_CHANNEL, any of the others can be commented out to remove the option and replace it with default behaviour.

Find it on GitHub here.

Expansion ideas:

  • More sequencer modes: random steps; random notes; forward and back; different skip modes; etc,.
  • Better use of the LEDs – e.g. different colours for sounding/silent steps.
  • Option to change the number of steps.
  • Expansion to two 8Angle units.

IMG_7100

M5Stack 8Encoder

This is a companion module to the 8Angle but this time has 8 switched rotary encoders available over I2C.  Again the specification states it should be used with 5V, but I’ve found it seems to be ok with the 3V3 XIAO’s I2C Grove links.  Again, use at your own risk!  Once again these came with a cable using the following colour code:

  • Black – GND
  • Red – VCC
  • Yellow – SDA
  • White- SCL

Also once again there is an Arduino library available, which can be found here: https://github.com/m5stack/M5Unit-8Encoder.  To use this with the XIAO however there is a minor patch required.

In UNIT_8ENCODER.cpp, in the function UNIT_8ENCODER::begin there is a call to _wire->begin which takes three parameters.  This has to be changed to a void function call:

// Change the line
  _wire->begin(_sda, _scl, _speed);
// To:
  _wire->begin();

When compiling there is a warning that the library says it is for the ESP32 but it is being built for the SAMD architecture.  This may be a symptom of that.

Here is some test code to show how it works.

#include <Wire.h>
#include <UNIT_8ENCODER.h>

UNIT_8ENCODER re;

void setup() {
  Serial.begin(9600);
  re.begin(&Wire, ENCODER_ADDR, 0, 0, 0);
}

void loop() {
  if (re.getSwitchStatus()) {
    for (int i=0; i<8; i++) {
      int32_t enc = re.getEncoderValue(i);
      uint8_t btn = re.getButtonStatus(i);
      int32_t inc = re.getIncrementValue(i);

      if (btn) {
        Serial.print("[1] ");
      } else {
        Serial.print("[0] ");
      }
      Serial.print(enc);
      Serial.print(" (");
      Serial.print(inc);
      Serial.print(")\t");
    }
    Serial.print("\n");
  }
}

It is possible to read the absolute “count” from the encoder as a signed 32-bit value (-2,147,483,648 to 2,147,483,647) and the increment since the last counter, again as a signed 32-bit value (full range, but typically +/- single units!).  There is also the encoder’s switch (called a button in the API) as well as the 8Encoder’s sliding switch.

Again individual LED colours can be set using setLEDColor(led, RGB).

The next project shows how this can be used as a MIDI Control Change controller.

M5Stack 8Angle and 8Encoder MIDI CC Controller

Additional parts required:

  • M5Stack 8Angle I2C potentiometer bank.
  • OR M5Stack 8Encoder I2C rotary encoder bank.

Following on from the above two projects, this presents a configurable MIDI CC controller for either the 8Angle or 8Encoder.  It also presents a graphic display of the current CC value on the OLED display on the XIAO expander module.

IMG_7101

The choice of device is defined at the top of the code – the one not being used must be commented out:

// Use one of these (and comment out the other)
//#define M5STACK_8ENCODER 1
#define M5STACK_8ANGLE 1

The eight MIDI Control Change messages to use are set up next, with the defaults as follows:

uint8_t cc[NUM_CC]={
  1, // Modulation
  2, // Breath
  7, // Channel volume
  8, // Balance
 10, // Pan
 11, // Expression
 12, // Effect Control 1
 13, // Effect Control 2
};

CC values will only be transmitted when something changes and will be sent over both USB and serial MIDI.

Find it on GitHub here.

Expansion ideas:

  • It would be fairly easy to swap so that it is a single MIDI CC value but across 8 MIDI channels (e.g. for use with channel volume).
  • The slider switch could be used to change to a different “bank” of MIDI CC messages to give another 8 controls.
  • Each encoders button could be used to trigger MIDI messages too.
  • A graphical sequencer using the OLED display with the 8Encoder might be an interesting project too.

Pimoroni IO Expander Breakout

Pimoroni designed and sell an I2C IO Expander that is particularly suited to use with the XIAO Expander.  Find it here.  It is part of their “breakout garden” range and as well as python support has an Arduino port of their library which can be found here: https://github.com/ZodiusInfuser/IOExpander_Library

XIAO-Expansion-IOExpander-Analog_bb

This allows eight potentiometers to be connected over I2C, so I’ve used it with my Analog IO Board PCB as shown above, but eight individual potentiometers could be used instead.  Each just needs a connection to VIN and GND.

Note that the cables I’m using here (Grove to header pin sockets) are using the following colour code (which is opposite to those used with the M5Stack modules):

  • Black – GND
  • Red – VCC
  • White – SDA
  • Yellow – SCL

IMG_7169

Using the library is pretty straight forward.  Here is my standard “analog pot test” code using the IOExpander library.

#include <IOExpander.h>
IOExpander ioe(Wire, 0x18);
void setup() {
  Serial.begin(9600);
  Wire.begin();
  if(!ioe.initialise()) {
    while(true)
    delay(10);
  }

  ioe.setAdcVref(3.3f);
  for (int i=0; i<8; i++) {
    ioe.setMode(7+i, IOExpander::PIN_ADC);
  }
}
void loop() {
  for (int i=0; i<8; i++) {
    uint16_t adc = ioe.input(7+i);
    Serial.print(adc);
    Serial.print("\t");
  }
  Serial.print("\n");
  delay(200);
}

The potentiometers have 12-bit resolution, giving a value between 0 and 4095.  Consequently, a bit-shift of 5 will transform this into the MIDI range of 0 to 127.

There is a version of the XIAO Expander MIDI Controller code for the Pimoroni module on GitHub here.

IMG_7168

HobbyTronics 10 Channel ADC I2C

One other device that caught my eye was the HobbyTronics 10 Channel ADC I2C that they’ve developed and sell here: https://www.hobbytronics.co.uk/electronic-components/misc-ic/adc-i2c-slave.

It is basically a microcontroller with firmware to provide 10 channels of analog input over the I2C bus in a single 20-pin DIP package.

XIAO-Expansion-HT-I2C-Analog_bb

I’ve wired it up on solderless breadboard to my Analog IO Board PCB.  This means I’m only using 8 of the inputs of course.  There are two spare.  There are a couple of things to note about this circuit:

  • The I2C address is selectable between 40 (0x28) and 47 using the three address lines.  I’ve set them all to zero for the default address of 40.
  • I’ve added a 100nF capacitor across the chip’s supply.
  • I’ve also added a 10pF capacitor to the I2C SCL signal.

Why that last addition?  I had a weird issue where the device would only send data to my XIAO if an oscilloscope probe was connected to the I2C SCL signal!  From conversations on Mastodon, we concluded the capacitance of the probe was having an effect on the signal, so the addition of a 10pF capacitor between SCL and GND seems to have fixed it.  It may well be something to do with the solderless breadboard, signal path lengths, and possibly a dodgy ground.  Basically it was behaving in a very weird way (it would read zeros ok, but if it read a non-zero value at all, it would often lock up the I2C bus).

There is test code provided in the datasheet linked from the product page.

Here is a version of the XIAO Expander MIDI Controller code for the HobbyTronics module on GitHub here.

IMG_7183

Closing Thoughts

Expanding via I2C to additional IO is relatively straight forward, and as can be seen here there are many options.  Having now experimented with them all I am wondering about a new version of my Analog IO PCB that supports a microcontroller that could provide an I2C link to another board in a similar manner to the HobbyTronics one.

But to be honest, all of the modules listed here are so neat and relatively easy to use, there really is little point other than the satisfaction of having done it, and the ability to customise (and publish) the code that allows it.

One thing that might be worth exploring is some kind of I2C button keyboard interface.  But if I’m getting to the point of putting a microcontroller on a device to talk I2C, then I may as well have it talk straight MIDI 🙂

Kevin

Leave a comment