Add PixelStomp MUX driver (DAT=9, LD=10, CLK=11, DI=12)
- New PixelStompMux class with shift register read/write - Read 10 buttons via DI (active LOW) - Drive 10 LEDs via DAT (shift out + latch) - LED startup animation uses MUX - Switch polling reads from MUX shift register - MUX instance shared between switch and LED drivers
This commit is contained in:
@@ -23,6 +23,8 @@ struct LedState {
|
|||||||
bool active;
|
bool active;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PixelStompMux;
|
||||||
|
|
||||||
class DefaultLedStub : public LedStub {
|
class DefaultLedStub : public LedStub {
|
||||||
private:
|
private:
|
||||||
static const uint8_t NUM_LEDS = 10;
|
static const uint8_t NUM_LEDS = 10;
|
||||||
@@ -34,4 +36,6 @@ public:
|
|||||||
void begin() override;
|
void begin() override;
|
||||||
void set_led_state(uint8_t note, uint8_t channel, uint8_t velocity) override;
|
void set_led_state(uint8_t note, uint8_t channel, uint8_t velocity) override;
|
||||||
void clear_all() override;
|
void clear_all() override;
|
||||||
|
|
||||||
|
void set_mux(PixelStompMux* mux);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class PixelStompMux {
|
||||||
|
public:
|
||||||
|
static const uint8_t NUM_INPUTS = 10;
|
||||||
|
static const uint8_t NUM_OUTPUTS = 10;
|
||||||
|
|
||||||
|
PixelStompMux(uint8_t dat_pin, uint8_t ld_pin, uint8_t clk_pin, uint8_t di_pin);
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
uint16_t read_buttons();
|
||||||
|
bool is_button_pressed(uint8_t index);
|
||||||
|
|
||||||
|
void write_leds(uint16_t led_state);
|
||||||
|
void set_led(uint8_t index, bool on);
|
||||||
|
void clear_all();
|
||||||
|
|
||||||
|
void dump();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t pin_dat;
|
||||||
|
uint8_t pin_ld;
|
||||||
|
uint8_t pin_clk;
|
||||||
|
uint8_t pin_di;
|
||||||
|
|
||||||
|
uint16_t last_button_state;
|
||||||
|
uint16_t current_led_state;
|
||||||
|
|
||||||
|
void shift_out(uint16_t data, uint8_t bits);
|
||||||
|
uint16_t shift_in(uint8_t bits);
|
||||||
|
void pulse_pin(uint8_t pin, uint8_t level, uint16_t duration_us = 1);
|
||||||
|
};
|
||||||
@@ -21,6 +21,8 @@ struct SwitchState {
|
|||||||
uint32_t debounce_time;
|
uint32_t debounce_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PixelStompMux;
|
||||||
|
|
||||||
class DefaultSwitchStub : public SwitchStub {
|
class DefaultSwitchStub : public SwitchStub {
|
||||||
private:
|
private:
|
||||||
static const uint8_t NUM_SWITCHES = 10;
|
static const uint8_t NUM_SWITCHES = 10;
|
||||||
@@ -33,4 +35,6 @@ public:
|
|||||||
bool is_pressed(uint8_t switch_id) override;
|
bool is_pressed(uint8_t switch_id) override;
|
||||||
void configure_switch(uint8_t switch_id, uint8_t gpio_pin) override;
|
void configure_switch(uint8_t switch_id, uint8_t gpio_pin) override;
|
||||||
void set_debounce_time(uint32_t time_ms) override;
|
void set_debounce_time(uint32_t time_ms) override;
|
||||||
|
|
||||||
|
void set_mux(PixelStompMux* mux);
|
||||||
};
|
};
|
||||||
|
|||||||
+20
-14
@@ -1,9 +1,8 @@
|
|||||||
#include "led_stub.h"
|
#include "led_stub.h"
|
||||||
|
#include "pixel_stomp_mux.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
static const uint8_t LED_PINS[10] = {
|
static PixelStompMux* mux_ptr = nullptr;
|
||||||
38, 39, 40, 41, 42, 45, 46, 47, 48, 21
|
|
||||||
};
|
|
||||||
|
|
||||||
DefaultLedStub::DefaultLedStub() : initialized(false) {
|
DefaultLedStub::DefaultLedStub() : initialized(false) {
|
||||||
for (int i = 0; i < NUM_LEDS; i++) {
|
for (int i = 0; i < NUM_LEDS; i++) {
|
||||||
@@ -15,26 +14,31 @@ DefaultLedStub::DefaultLedStub() : initialized(false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DefaultLedStub::set_mux(PixelStompMux* mux) {
|
||||||
|
mux_ptr = mux;
|
||||||
|
}
|
||||||
|
|
||||||
void DefaultLedStub::begin() {
|
void DefaultLedStub::begin() {
|
||||||
for (int i = 0; i < NUM_LEDS; i++) {
|
Serial.println("[LED] Using PixelStomp MUX for LED output");
|
||||||
pinMode(LED_PINS[i], OUTPUT);
|
|
||||||
digitalWrite(LED_PINS[i], LOW);
|
|
||||||
}
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
Serial.println("[LED] Startup animation...");
|
Serial.println("[LED] Startup animation...");
|
||||||
|
|
||||||
for (int i = 0; i < NUM_LEDS; i++) {
|
for (int i = 0; i < NUM_LEDS; i++) {
|
||||||
digitalWrite(LED_PINS[i], HIGH);
|
if (mux_ptr) {
|
||||||
Serial.printf("[LED] LED %d ON (GPIO %d)\n", i, LED_PINS[i]);
|
mux_ptr->set_led(i, true);
|
||||||
|
}
|
||||||
|
Serial.printf("[LED] LED %d ON\n", i);
|
||||||
delay(150);
|
delay(150);
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(300);
|
delay(300);
|
||||||
|
|
||||||
for (int i = NUM_LEDS - 1; i >= 0; i--) {
|
for (int i = NUM_LEDS - 1; i >= 0; i--) {
|
||||||
digitalWrite(LED_PINS[i], LOW);
|
if (mux_ptr) {
|
||||||
Serial.printf("[LED] LED %d OFF (GPIO %d)\n", i, LED_PINS[i]);
|
mux_ptr->set_led(i, false);
|
||||||
|
}
|
||||||
|
Serial.printf("[LED] LED %d OFF\n", i);
|
||||||
delay(100);
|
delay(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +57,9 @@ void DefaultLedStub::set_led_state(uint8_t note, uint8_t channel, uint8_t veloci
|
|||||||
led_states[led_index].active = (velocity > 0);
|
led_states[led_index].active = (velocity > 0);
|
||||||
led_states[led_index].timestamp = millis();
|
led_states[led_index].timestamp = millis();
|
||||||
|
|
||||||
digitalWrite(LED_PINS[led_index], velocity > 0 ? HIGH : LOW);
|
if (mux_ptr) {
|
||||||
|
mux_ptr->set_led(led_index, velocity > 0);
|
||||||
|
}
|
||||||
|
|
||||||
Serial.printf("[LED] Note %d -> LED %d Ch %d Vel %d (%s)\n",
|
Serial.printf("[LED] Note %d -> LED %d Ch %d Vel %d (%s)\n",
|
||||||
note, led_index, channel, velocity,
|
note, led_index, channel, velocity,
|
||||||
@@ -67,9 +73,9 @@ void DefaultLedStub::clear_all() {
|
|||||||
for (int i = 0; i < NUM_LEDS; i++) {
|
for (int i = 0; i < NUM_LEDS; i++) {
|
||||||
led_states[i].active = false;
|
led_states[i].active = false;
|
||||||
led_states[i].velocity = 0;
|
led_states[i].velocity = 0;
|
||||||
if (initialized) {
|
|
||||||
digitalWrite(LED_PINS[i], LOW);
|
|
||||||
}
|
}
|
||||||
|
if (mux_ptr) {
|
||||||
|
mux_ptr->clear_all();
|
||||||
}
|
}
|
||||||
Serial.println("[LED] All cleared");
|
Serial.println("[LED] All cleared");
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -3,10 +3,13 @@
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "midi_transport.h"
|
#include "midi_transport.h"
|
||||||
|
#include "pixel_stomp_mux.h"
|
||||||
#include "led_stub.h"
|
#include "led_stub.h"
|
||||||
#include "switch_stub.h"
|
#include "switch_stub.h"
|
||||||
#include "app_task.h"
|
#include "app_task.h"
|
||||||
|
|
||||||
|
PixelStompMux mux(9, 10, 11, 12);
|
||||||
|
|
||||||
DefaultLedStub led_driver;
|
DefaultLedStub led_driver;
|
||||||
DefaultSwitchStub switch_driver;
|
DefaultSwitchStub switch_driver;
|
||||||
UsbMidiTransport midi_transport;
|
UsbMidiTransport midi_transport;
|
||||||
@@ -34,10 +37,15 @@ void setup() {
|
|||||||
Serial.println(" Board: ESP32-S3-WROOM-1");
|
Serial.println(" Board: ESP32-S3-WROOM-1");
|
||||||
Serial.println("=================================");
|
Serial.println("=================================");
|
||||||
|
|
||||||
|
Serial.println("[INIT] Initializing PixelStomp MUX...");
|
||||||
|
mux.begin();
|
||||||
|
|
||||||
Serial.println("[INIT] Starting LED startup animation...");
|
Serial.println("[INIT] Starting LED startup animation...");
|
||||||
|
led_driver.set_mux(&mux);
|
||||||
led_driver.begin();
|
led_driver.begin();
|
||||||
|
|
||||||
Serial.println("[INIT] Initializing switches...");
|
Serial.println("[INIT] Initializing switches via MUX...");
|
||||||
|
switch_driver.set_mux(&mux);
|
||||||
switch_driver.begin();
|
switch_driver.begin();
|
||||||
|
|
||||||
Serial.println("[INIT] Initializing USB MIDI...");
|
Serial.println("[INIT] Initializing USB MIDI...");
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
#include "pixel_stomp_mux.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
static const char* TAG = "MUX";
|
||||||
|
|
||||||
|
PixelStompMux::PixelStompMux(uint8_t dat, uint8_t ld, uint8_t clk, uint8_t di)
|
||||||
|
: pin_dat(dat), pin_ld(ld), pin_clk(clk), pin_di(di),
|
||||||
|
last_button_state(0), current_led_state(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixelStompMux::begin() {
|
||||||
|
pinMode(pin_dat, OUTPUT);
|
||||||
|
pinMode(pin_ld, OUTPUT);
|
||||||
|
pinMode(pin_clk, OUTPUT);
|
||||||
|
pinMode(pin_di, INPUT_PULLUP);
|
||||||
|
|
||||||
|
digitalWrite(pin_dat, LOW);
|
||||||
|
digitalWrite(pin_ld, LOW);
|
||||||
|
digitalWrite(pin_clk, LOW);
|
||||||
|
|
||||||
|
Serial.printf("[MUX] Init DAT=%d LD=%d CLK=%d DI=%d\n",
|
||||||
|
pin_dat, pin_ld, pin_clk, pin_di);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PixelStompMux::read_buttons() {
|
||||||
|
pulse_pin(pin_ld, HIGH);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
pulse_pin(pin_ld, LOW);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
|
||||||
|
uint16_t state = shift_in(NUM_INPUTS);
|
||||||
|
last_button_state = state;
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PixelStompMux::is_button_pressed(uint8_t index) {
|
||||||
|
if (index >= NUM_INPUTS) return false;
|
||||||
|
|
||||||
|
uint16_t state = read_buttons();
|
||||||
|
return !(state & (1 << index));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixelStompMux::write_leds(uint16_t led_state) {
|
||||||
|
current_led_state = led_state;
|
||||||
|
shift_out(led_state, NUM_OUTPUTS);
|
||||||
|
pulse_pin(pin_ld, HIGH);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
pulse_pin(pin_ld, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixelStompMux::set_led(uint8_t index, bool on) {
|
||||||
|
if (index >= NUM_OUTPUTS) return;
|
||||||
|
|
||||||
|
if (on) {
|
||||||
|
current_led_state |= (1 << index);
|
||||||
|
} else {
|
||||||
|
current_led_state &= ~(1 << index);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_leds(current_led_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixelStompMux::clear_all() {
|
||||||
|
write_leds(0x0000);
|
||||||
|
Serial.println("[MUX] All LEDs off");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixelStompMux::dump() {
|
||||||
|
uint16_t buttons = read_buttons();
|
||||||
|
Serial.printf("[MUX] Buttons: 0x%03X LEDs: 0x%03X\n", buttons, current_led_state);
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_INPUTS; i++) {
|
||||||
|
bool pressed = !(buttons & (1 << i));
|
||||||
|
bool led_on = current_led_state & (1 << i);
|
||||||
|
if (pressed || led_on) {
|
||||||
|
Serial.printf(" [%d] Button:%s LED:%s\n", i,
|
||||||
|
pressed ? "PRESS" : "off",
|
||||||
|
led_on ? "ON" : "off");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixelStompMux::shift_out(uint16_t data, uint8_t bits) {
|
||||||
|
for (int i = bits - 1; i >= 0; i--) {
|
||||||
|
digitalWrite(pin_dat, (data >> i) & 1);
|
||||||
|
pulse_pin(pin_clk, HIGH);
|
||||||
|
pulse_pin(pin_clk, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PixelStompMux::shift_in(uint8_t bits) {
|
||||||
|
uint16_t data = 0;
|
||||||
|
|
||||||
|
for (int i = bits - 1; i >= 0; i--) {
|
||||||
|
bool bit = digitalRead(pin_di);
|
||||||
|
if (bit) {
|
||||||
|
data |= (1 << i);
|
||||||
|
}
|
||||||
|
pulse_pin(pin_clk, HIGH);
|
||||||
|
pulse_pin(pin_clk, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixelStompMux::pulse_pin(uint8_t pin, uint8_t level, uint16_t duration_us) {
|
||||||
|
digitalWrite(pin, level);
|
||||||
|
delayMicroseconds(duration_us);
|
||||||
|
}
|
||||||
+11
-18
@@ -1,14 +1,13 @@
|
|||||||
#include "switch_stub.h"
|
#include "switch_stub.h"
|
||||||
|
#include "pixel_stomp_mux.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
static const uint8_t SWITCH_PINS[10] = {
|
static PixelStompMux* mux_ptr = nullptr;
|
||||||
2, 3, 4, 5, 6, 7, 15, 16, 17, 18
|
|
||||||
};
|
|
||||||
|
|
||||||
DefaultSwitchStub::DefaultSwitchStub() : initialized(false) {
|
DefaultSwitchStub::DefaultSwitchStub() : initialized(false) {
|
||||||
for (int i = 0; i < NUM_SWITCHES; i++) {
|
for (int i = 0; i < NUM_SWITCHES; i++) {
|
||||||
switch_states[i].id = i;
|
switch_states[i].id = i;
|
||||||
switch_states[i].gpio_pin = SWITCH_PINS[i];
|
switch_states[i].gpio_pin = 0;
|
||||||
switch_states[i].current_state = false;
|
switch_states[i].current_state = false;
|
||||||
switch_states[i].previous_state = false;
|
switch_states[i].previous_state = false;
|
||||||
switch_states[i].last_change_time = 0;
|
switch_states[i].last_change_time = 0;
|
||||||
@@ -17,24 +16,21 @@ DefaultSwitchStub::DefaultSwitchStub() : initialized(false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DefaultSwitchStub::begin() {
|
void DefaultSwitchStub::begin() {
|
||||||
for (int i = 0; i < NUM_SWITCHES; i++) {
|
Serial.println("[SW] Using PixelStomp MUX for button input");
|
||||||
pinMode(switch_states[i].gpio_pin, INPUT_PULLUP);
|
|
||||||
}
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
Serial.printf("[SW] %d switches on GPIOs: ", NUM_SWITCHES);
|
}
|
||||||
for (int i = 0; i < NUM_SWITCHES; i++) {
|
|
||||||
Serial.printf("%d ", switch_states[i].gpio_pin);
|
void DefaultSwitchStub::set_mux(PixelStompMux* mux) {
|
||||||
}
|
mux_ptr = mux;
|
||||||
Serial.println();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DefaultSwitchStub::is_pressed(uint8_t switch_id) {
|
bool DefaultSwitchStub::is_pressed(uint8_t switch_id) {
|
||||||
if (!initialized || switch_id >= NUM_SWITCHES) {
|
if (!initialized || switch_id >= NUM_SWITCHES || !mux_ptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SwitchState& sw = switch_states[switch_id];
|
SwitchState& sw = switch_states[switch_id];
|
||||||
bool raw = (digitalRead(sw.gpio_pin) == LOW);
|
bool raw = mux_ptr->is_button_pressed(switch_id);
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
|
|
||||||
if (raw != sw.previous_state) {
|
if (raw != sw.previous_state) {
|
||||||
@@ -54,10 +50,7 @@ bool DefaultSwitchStub::is_pressed(uint8_t switch_id) {
|
|||||||
void DefaultSwitchStub::configure_switch(uint8_t switch_id, uint8_t gpio_pin) {
|
void DefaultSwitchStub::configure_switch(uint8_t switch_id, uint8_t gpio_pin) {
|
||||||
if (switch_id >= NUM_SWITCHES) return;
|
if (switch_id >= NUM_SWITCHES) return;
|
||||||
switch_states[switch_id].gpio_pin = gpio_pin;
|
switch_states[switch_id].gpio_pin = gpio_pin;
|
||||||
if (initialized) {
|
Serial.printf("[SW] Switch %d remapped to GPIO %d\n", switch_id, gpio_pin);
|
||||||
pinMode(gpio_pin, INPUT_PULLUP);
|
|
||||||
}
|
|
||||||
Serial.printf("[SW] Switch %d -> GPIO %d\n", switch_id, gpio_pin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefaultSwitchStub::set_debounce_time(uint32_t time_ms) {
|
void DefaultSwitchStub::set_debounce_time(uint32_t time_ms) {
|
||||||
|
|||||||
Reference in New Issue
Block a user