Control Surface master
MIDI Control Surface library for Arduino
MCU-OLED-SSD1306.ino

MCU-OLED-SSD1306

An example demonstrating the use of DisplayElements to display information from the DAW on a small OLED display.

Boards:
Mega, Teensy 3.x, ESP32

Connections

Add a capacitor between the reset pin of the display and ground, and a resistor from reset to 3.3V. The values are not critical, 0.1µF and 10kΩ work fine.
You do need some way to reset the display, without it, it won't work.
Alternatively, you could use an IO pin from the Teensy to reset the display, but this just "wastes" a pin.

Behavior

Mapping

Map "Control Surface" as a Mackie Control Universal unit in your DAW.

Note
There seem to be some differences in the way some applications handle VU meters: some expect the hardware to decay automatically, some don't.
If you notice that the meters behave strangely, try both MCU::VUDecay::Hold and MCU::VUDecay::Default, or try a different decay time.

Written by PieterP, 2019-11-12
https://github.com/tttapa/Control-Surface

#include <Control_Surface.h> // Include the Control Surface library
// Include the display interface you'd like to use
// ----------------------------- MIDI Interface ----------------------------- //
// ========================================================================== //
/*
Instantiate a MIDI interface to use for the Control Surface.
*/
// USBDebugMIDI_Interface midi(115200);
// ----------------------------- Display setup ------------------------------ //
// ========================================================================== //
/*
Instantiate and initialize the SSD1306 OLED display
*/
constexpr uint8_t SCREEN_WIDTH = 128;
constexpr uint8_t SCREEN_HEIGHT = 64;
constexpr int8_t OLED_DC = 17; // Data/Command pin of the display
constexpr int8_t OLED_reset = -1; // Use the external RC circuit for reset
constexpr int8_t OLED_CS = 10; // Chip Select pin of the display
constexpr uint32_t SPI_Frequency = SPI_MAX_SPEED;
// Instantiate the displays
Adafruit_SSD1306 ssd1306Display {
SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, OLED_DC,
OLED_reset, OLED_CS, SPI_Frequency,
};
// --------------------------- Display interface ---------------------------- //
// ========================================================================== //
// Implement the display interface, specifically, the begin and drawBackground
// methods.
class MySSD1306_DisplayInterface : public SSD1306_DisplayInterface {
public:
MySSD1306_DisplayInterface(Adafruit_SSD1306 &display)
void begin() override {
// Initialize the Adafruit_SSD1306 display
if (!disp.begin())
FATAL_ERROR(F("SSD1306 allocation failed."), 0x1306);
// If you override the begin method, remember to call the super class method
}
void drawBackground() override { disp.drawLine(1, 8, 126, 8, WHITE); }
} display = ssd1306Display;
// ------------------------------- Bank setup ------------------------------- //
// ========================================================================== //
/*
Create a bank and a bank selector to change its setting.
*/
Bank<4> bank(2); // Create a new bank with two tracks per bank
// Create a new bank selector to control the bank using two push buttons
IncrementDecrementSelector<4> bankselector {bank, {5, 6}, Wrap::Wrap};
// -------------------------- MIDI Input Elements --------------------------- //
// ========================================================================== //
/*
Define all elements that listen for MIDI messages.
*/
// Time display keeps track of the bar counter
MCU::TimeDisplay timedisplay {};
// Play / Record
// Mute
{bank, MCU::MUTE_1},
{bank, MCU::MUTE_2},
};
// Solo
{bank, MCU::SOLO_1},
{bank, MCU::SOLO_2},
};
// Record arm / ready
{bank, MCU::REC_RDY_1},
{bank, MCU::REC_RDY_2},
};
// VU meters
{bank, 1, MCU::VUDecay::Hold},
{bank, 2, MCU::VUDecay::Hold},
};
// VPot rings
{bank, 1},
{bank, 2},
};
// ---------------------------- Display Elements ---------------------------- //
// ========================================================================== //
/*
Define all display elements that display the state of the input elements.
*/
// Time display
MCU::TimeDisplayDisplay timedisplaydisplay {
// position (0, 0), font size (1)
display, timedisplay, {0, 0}, 1, WHITE,
};
// Play / Record
BitmapDisplay<> playDisp {
display, play, XBM::play_7, {16 + 64, 0}, WHITE,
};
BitmapDisplay<> recordDisp {
display, record, XBM::record_7, {26 + 64, 0}, WHITE,
};
// Mute
BitmapDisplay<> muteDisp[] {
{display, mute[0], XBM::mute_10B, {14, 50}, WHITE},
{display, mute[1], XBM::mute_10B, {14 + 64, 50}, WHITE},
};
// Solo
BitmapDisplay<> soloDisp[] {
{display, solo[0], XBM::solo_10B, {14, 50}, WHITE},
{display, solo[1], XBM::solo_10B, {14 + 64, 50}, WHITE},
};
BitmapDisplay<> rudeSoloDisp {
display, rudeSolo, XBM::solo_7, {36 + 64, 0}, WHITE};
// Record arm / ready
BitmapDisplay<> recrdyDisp[] {
{display, recrdy[0], XBM::rec_rdy_10B, {14 + 14, 50}, WHITE},
{display, recrdy[1], XBM::rec_rdy_10B, {14 + 14 + 64, 50}, WHITE},
};
// VU meters
MCU::VUDisplay<> vuDisp[] {
// position (32+11, 60), width (16), bar height (3) px, bar spacing (1) px
{display, vu[0], {32 + 11, 60}, 16, 3, 1, WHITE},
{display, vu[1], {32 + 11 + 64, 60}, 16, 3, 1, WHITE},
};
// VPot rings
MCU::VPotDisplay<> vpotDisp[] {
// position (0, 10), outer radius (16) px, inner radius (13) px
{display, vpot[0], {0, 10}, 16, 13, WHITE},
{display, vpot[1], {64, 10}, 16, 13, WHITE},
};
// Bank seting
BankDisplay bankDisp[] {
// first track of the bank (1), position (0, 50), font size (2)
{display, bank, 1, {0, 50}, 2, WHITE},
{display, bank, 2, {64, 50}, 2, WHITE},
};
// --------------------------------- Setup ---------------------------------- //
// ========================================================================== //
void setup() {
// Correct relative mode for MCU rotary encoders
Control_Surface.begin(); // Initialize Control Surface
}
// ---------------------------------- Loop ---------------------------------- //
// ========================================================================== //
void loop() {
Control_Surface.loop(); // Refresh all elements
}
The main header file that includes all Control-Surface header files.
Control_Surface_ & Control_Surface
A predefined instance of the Control Surface to use in the Arduino sketches.
@ MACKIE_CONTROL_RELATIVE
Relative mode used by the Mackie Control Universal protocol.
@ Wrap
When the maximum (minimum) setting is reached, wrap around to the minimum (maximum) setting.
A class for displaying the setting of a Bank object.
A class that groups Bankable MIDI Output Elements and Bankable MIDI Input Elements,...
Definition: Bank.hpp:91
Generic base class for classes that listen for MIDI Note, Control Change and Key Pressure events on a...
A class that displays a bitmap depending on the state of a MIDINote or any other object that has a ge...
void begin()
Initialize the Control_Surface.
void loop()
Update all MIDI elements, send MIDI events and read MIDI input.
virtual void begin()
Initialize the display.
Selector with two buttons (one to increment, one to decrement).
A MIDI input element that represents a Mackie Control Universal VPot ring.
Definition: VPotRing.hpp:240
A MIDI input element that represents a Mackie Control Universal VU meter.
Definition: VU.hpp:297
Class that receives and stores the text of the Mackie Control Universal 7-segment time display.
Definition: TimeDisplay.hpp:16
Generic base class for classes that listen for MIDI Note, Control Change and Key Pressure events on a...
static void setMode(relativeCCmode mode)
Set the relative CC mode that's used.
This class creates a mapping between the Adafruit_SSD1306 display driver and the general display inte...
void drawBackground() override=0
Draw a custom background.
A class for MIDI interfaces sending MIDI messages over a USB MIDI connection.
#define FATAL_ERROR(msg, errc)
Print the error message and error code, and stop the execution.
Definition: Error.hpp:60
constexpr uint8_t MUTE_1
Mute 1 (In/Out)
Definition: MCU.hpp:40
constexpr uint8_t REC_RDY_2
Record/Ready 2 (In/Out)
Definition: MCU.hpp:23
constexpr uint8_t REC_RDY_1
Record/Ready 1 (In/Out)
Definition: MCU.hpp:22
constexpr uint8_t RECORD
Record (In/Out)
Definition: MCU.hpp:131
constexpr uint8_t SOLO_2
Solo 2 (In/Out)
Definition: MCU.hpp:32
constexpr uint8_t SOLO_1
Solo 1 (In/Out)
Definition: MCU.hpp:31
constexpr uint8_t PLAY
Play (In/Out)
Definition: MCU.hpp:130
constexpr uint8_t RUDE_SOLO
Rude solo light (In)
Definition: MCU.hpp:157
constexpr uint8_t MUTE_2
Mute 2 (In/Out)
Definition: MCU.hpp:41
constexpr static Frequency SPI_MAX_SPEED
constexpr unsigned int Hold
Don't decay automatically, hold the latest value until a new one is received.
Definition: VU.hpp:177
const XBitmap solo_7
XBitmap solo_7 (7px × 7px)
Definition: XBitmaps.hpp:130
const XBitmap record_7
XBitmap record_7 (7px × 7px)
Definition: XBitmaps.hpp:102
const XBitmap rec_rdy_10B
XBitmap rec_rdy_10B (10px × 10px)
Definition: XBitmaps.hpp:81
const XBitmap play_7
XBitmap play_7 (7px × 7px)
Definition: XBitmaps.hpp:67
const XBitmap solo_10B
XBitmap solo_10B (10px × 10px)
Definition: XBitmaps.hpp:116
const XBitmap mute_10B
XBitmap mute_10B (10px × 10px)
Definition: XBitmaps.hpp:39