Filter UI OLED XIAO RP2040 — Xiao Rp2040 simulation

An Oberheim-style filter response display on a 128x64 I2C OLED driven by a Seeed XIAO RP2040 with two potentiometers and a rotary encoder.

An interactive Xiao Rp2040 circuit simulation you can run free in your browser on Velxio, by bwei.

Components

Sketch code

//#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH  128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
#define OLED_ADDRESS  0x3C

// Hardware Pin Definitions for RP2040
#define PIN_CUTOFF    26 // ADC0 (Potentiometer 1)
#define PIN_RESONANCE 27 // ADC1 (Potentiometer 2)
#define PIN_ENCODER_A 2  // Quadrature Encoder A
#define PIN_ENCODER_B 3  // Quadrature Encoder B
#define PIN_ENCODER_SW 9;   // D9 - Encoder Click Switch

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Filter Shape Classification
enum FilterShape {
    SHAPE_LOWPASS,
    SHAPE_HIGHPASS,
    SHAPE_BANDPASS,
    SHAPE_NOTCH,
    SHAPE_ALLPASS
};

struct FilterMode {
    const char* name;
    FilterShape shape;
    uint8_t poles; // 1 to 4 poles (determines slope steepness)
};

// Oberheim Matrix-12 / Xpander Inspired Response Types
const FilterMode FILTER_MODES[] = {
    {"LP1",   SHAPE_LOWPASS,  1}, //1-Pole Lowpass
    {"LP2",   SHAPE_LOWPASS,  2},//2-Pole Lowpass
    {"LP3",   SHAPE_LOWPASS,  3},//3-Pole Lowpass
    {"LP4",   SHAPE_LOWPASS,  4},
    {"HP1",  SHAPE_HIGHPASS, 1},//1-Pole Highpass
    {"HP2",  SHAPE_HIGHPASS, 2},
    {"HP3",  SHAPE_HIGHPASS, 3},
    {"HP4",  SHAPE_HIGHPASS, 4},
    {"BP2",  SHAPE_BANDPASS, 2},//2-Pole Bandpass
    {"BP4",  SHAPE_BANDPASS, 4},
    {"N2",     SHAPE_NOTCH,    2},//2-Pole Notch
    {"N4",     SHAPE_NOTCH,    4},
    {"AP3",     SHAPE_ALLPASS,  3},//3-Pole Phase
    {"AP4",   SHAPE_ALLPASS,  4}//4-Pole Allpass
};

const uint8_t TOTAL_MODES = sizeof(FILTER_MODES) / sizeof(FILTER_MODES[0]);
volatile uint8_t currentModeIndex = 0;

// Encoder Interrupt Service Routine
void readEncoder() {
    static uint8_t lastState = 0;
    uint8_t a = digitalRead(PIN_ENCODER_A);
    uint8_t b = digitalRead(PIN_ENCODER_B);
    uint8_t currentState = (a << 1) | b;
    
    if (currentState != lastState && currentState == 0b11) {
        if (lastState == 0b01) {
            currentModeIndex = (currentModeIndex + 1) % TOTAL_MODES;
        } else if (lastState == 0b10) {
            currentModeIndex = (currentModeIndex == 0) ? TOTAL_MODES - 1 : currentModeIndex - 1;
            
        }
    }
    lastState = currentState;

}

void readEncoderMOI() {
    static uint8_t lastStateA = 0;
    uint8_t currentStateA = digitalRead(PIN_ENCODER_A);
    uint8_t currentStateB = digitalRead(PIN_ENCODER_B);

    if (currentStateA != lastStateA) {// On a un mouvement
    // Read pin B to determine the direction of rotation
    if (currentStateB != currentStateA) {
      // Clockwise rotation -> Increment (+1)
      currentModeIndex= (currentModeIndex + 1) % TOTAL_MODES;
    } else {
      // Counter-clockwise rotation -> Decrement (-1)
      if(currentModeIndex == 0){currentModeIndex=TOTAL_MODES - 1;}
      else{currentModeIndex--;}
    }
    //lastStateA = currentStateA; //marche mieux sans ça interrupt sur CHANGE
    }
}


void setup() {
    
    
    analogReadResoluti

More projects by bwei