From 58bdf0aac71827decfa8500e202384d6c07202aa Mon Sep 17 00:00:00 2001 From: Oliver Parczyk Date: Sat, 16 Dec 2023 11:18:51 +0100 Subject: [PATCH 1/7] Refactor variable names and types Neccessary because on ARM 'char' != int8_t but uint_8 Just declaring what know you want makes this far less confusing. see https://en.cppreference.com/w/cpp/language/types --- src/main.cpp | 64 ++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 675b1d6..6537301 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,15 +4,15 @@ #define MIDI_NAME {'P', 'i', 'n', 'g', 'b', 'o', 'a', 'r', 'd'} #define MIDI_NAME_LEN 9 -#define CHECK_PINS 9 +#define KEY_GROUP_NUM 9 #define KEY_PINS 6 +#define NUMBER_OF_KEYS 49 #define BOUNCE_TIME 5 #define POWER_SUPPLY_CHECK_PIN 13 -#define NUMBER_OF_KEYS 49 #define SELF_DRIVE_INTERVAL 100 -Bounce check_pins[CHECK_PINS] { +Bounce group_pins[KEY_GROUP_NUM] { {14, BOUNCE_TIME}, // not KEYS1..6 {15, BOUNCE_TIME}, // not KEYS7..12 {16, BOUNCE_TIME}, // not KEYS13..18 @@ -25,20 +25,20 @@ Bounce check_pins[CHECK_PINS] { }; // not KEY0%6..not KEY5%6 -const unsigned char key_pins[KEY_PINS] {2, 3, 4, 5, 6, 7}; +const uint8_t key_pins[KEY_PINS] {2, 3, 4, 5, 6, 7}; // Array of pressed keys (initially all 0) bool keys_pressed[NUMBER_OF_KEYS]; // K1, K2, K3, K4, K5, K12, K13, K14, K15 -const unsigned char self_drive_pins[CHECK_PINS] {8, 9, 10, 11, 12, 26, 23, 24, 25}; -volatile unsigned char curr_self_drive_pin = 0; +const uint8_t self_drive_pins[KEY_GROUP_NUM] {8, 9, 10, 11, 12, 26, 23, 24, 25}; +volatile uint8_t current_self_drive_pin = 0; IntervalTimer self_drive_timer = IntervalTimer(); // Map the current array and pressed key to a MIDI note -unsigned char mapToMidi(char curr_arr, char key) { - unsigned char offset = (curr_arr >> 1) * 12; +uint8_t mapToMidi(uint8_t active_key_group, uint8_t key) { + uint8_t offset = (active_key_group >> 1) * 12; // TODO: maybe we have to switch the notes and array offsets // Uneven offset are the upper octave, even the lower - if (curr_arr & 1) { + if (active_key_group & 1) { switch (key) { case 0: return offset + 42; // F#2 + offset case 1: return offset + 43; // G2 + offset @@ -63,18 +63,18 @@ unsigned char mapToMidi(char curr_arr, char key) { } // Check if any of the array pins fell since last time -char findCurrentArrPin() { - for (unsigned char i = 0; i < CHECK_PINS; i++) { +int8_t getActiveKeyGroup() { + for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) { // Update status - check_pins[i].update(); + group_pins[i].update(); // Check if the pin fell or is low // ! inverted - if (check_pins[i].fell()) return i; + if (group_pins[i].fell()) return i; } // If none fell we should have enough time to see which one is low - for (unsigned char i = 0; i < CHECK_PINS; i++) { - if (check_pins[i].read() == LOW) return i; + for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) { + if (group_pins[i].read() == LOW) return i; } // Default return @@ -84,17 +84,17 @@ char findCurrentArrPin() { // Set the next self drive pin FASTRUN void nextSelfDrivePin() { // Set the current pin to high - digitalWriteFast(self_drive_pins[curr_self_drive_pin], HIGH); + digitalWriteFast(self_drive_pins[current_self_drive_pin], HIGH); // Set the next pin - curr_self_drive_pin = (curr_self_drive_pin + 1) % CHECK_PINS; + current_self_drive_pin = (current_self_drive_pin + 1) % KEY_GROUP_NUM; } // Interrupt for power supply check FASTRUN void powerStateChanged() { - unsigned char state = digitalReadFast(POWER_SUPPLY_CHECK_PIN); + uint8_t state = digitalReadFast(POWER_SUPPLY_CHECK_PIN); // ! inverted if (state == LOW) { - curr_self_drive_pin = 0; + current_self_drive_pin = 0; self_drive_timer.begin(nextSelfDrivePin, SELF_DRIVE_INTERVAL); } else { self_drive_timer.end(); @@ -104,11 +104,11 @@ FASTRUN void powerStateChanged() { // Initial start function void setup() { // Set all in- and outputs - for (unsigned char i = 0; i < CHECK_PINS; i++) { - pinMode(check_pins[i].getPin(), INPUT); + for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) { + pinMode(group_pins[i].getPin(), INPUT); pinMode(self_drive_pins[i], INPUT); } - for (unsigned char i = 0; i < KEY_PINS; i++) { + for (uint8_t i = 0; i < KEY_PINS; i++) { pinMode(key_pins[i], INPUT); } pinMode(POWER_SUPPLY_CHECK_PIN, INPUT); @@ -121,32 +121,32 @@ void setup() { // Main loop void loop() { // Find active arr pin - char curr_arr = findCurrentArrPin(); + int8_t active_key_group = getActiveKeyGroup(); // If none is active, we do nothing, else we check the keys - if (curr_arr >= 0) { + if (active_key_group >= 0) { // Get all the key values ans send the MIDI message if needed - unsigned char value; + uint8_t value; - for (unsigned char i = 0; i < KEY_PINS; i++) { + for (uint8_t i = 0; i < KEY_PINS; i++) { value = digitalReadFast(key_pins[i]); // If the key is pressed, we send a MIDI message and set the entry in the array // ! inverted if (value == LOW) { // Check if the key is not already pressed - if (keys_pressed[curr_arr * 6 + i] == 0) { + if (keys_pressed[active_key_group * 6 + i] == 0) { // Send MIDI message - usbMIDI.sendNoteOn(mapToMidi(curr_arr, i), 127, 1); + usbMIDI.sendNoteOn(mapToMidi(active_key_group, i), 127, 1); // Set the entry in the array - keys_pressed[curr_arr * 6 + i] = 1; + keys_pressed[active_key_group * 6 + i] = 1; } } else { // Check if the key is not already released - if (keys_pressed[curr_arr * 6 + i] == 1) { + if (keys_pressed[active_key_group * 6 + i] == 1) { // Send MIDI message - usbMIDI.sendNoteOff(mapToMidi(curr_arr, i), 0, 1); + usbMIDI.sendNoteOff(mapToMidi(active_key_group, i), 0, 1); // Set the entry in the array - keys_pressed[curr_arr * 6 + i] = 0; + keys_pressed[active_key_group * 6 + i] = 0; } } } From 030f2a39ae7bd8acdf3d22d9b40a6a894e395105 Mon Sep 17 00:00:00 2001 From: Oliver Parczyk Date: Sat, 16 Dec 2023 11:47:33 +0100 Subject: [PATCH 2/7] Remove debounce library dependency Debouncing, the way it was done may have been appropriate for human input, but is wholly inadequate for the sequential scanning of the host keyboard IC. It is however neccessary to provide something like debounce, because the teensy and host IC aren't syncronized. --- platformio.ini | 2 -- src/main.cpp | 52 +++++++++++++++++++++----------------------------- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/platformio.ini b/platformio.ini index 111ac9f..98678c2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,6 +12,4 @@ platform = teensy board = teensylc framework = arduino -lib_deps = - thomasfredericks/Bounce2@^2.71 build_flags = -D USB_MIDI -D TEENSY_OPT_FASTEST \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 6537301..20976f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,4 @@ #include -#include #define MIDI_NAME {'P', 'i', 'n', 'g', 'b', 'o', 'a', 'r', 'd'} #define MIDI_NAME_LEN 9 @@ -7,27 +6,19 @@ #define KEY_GROUP_NUM 9 #define KEY_PINS 6 #define NUMBER_OF_KEYS 49 -#define BOUNCE_TIME 5 + +#define DEBOUNCE_TIMES 2 + #define POWER_SUPPLY_CHECK_PIN 13 #define SELF_DRIVE_INTERVAL 100 -Bounce group_pins[KEY_GROUP_NUM] { - {14, BOUNCE_TIME}, // not KEYS1..6 - {15, BOUNCE_TIME}, // not KEYS7..12 - {16, BOUNCE_TIME}, // not KEYS13..18 - {17, BOUNCE_TIME}, // not KEYS19..24 - {18, BOUNCE_TIME}, // not KEYS25..30 - {19, BOUNCE_TIME}, // not KEYS31..36 - {20, BOUNCE_TIME}, // not KEYS37..42 - {21, BOUNCE_TIME}, // not KEYS43..48 - {22, BOUNCE_TIME} // not KEYS49 -}; +const uint8_t group_pins[KEY_GROUP_NUM] {14, 15, 16, 17, 18, 19, 20, 21, 22}; // not KEY0%6..not KEY5%6 const uint8_t key_pins[KEY_PINS] {2, 3, 4, 5, 6, 7}; // Array of pressed keys (initially all 0) -bool keys_pressed[NUMBER_OF_KEYS]; +uint8_t keys_pressed[NUMBER_OF_KEYS]; // K1, K2, K3, K4, K5, K12, K13, K14, K15 const uint8_t self_drive_pins[KEY_GROUP_NUM] {8, 9, 10, 11, 12, 26, 23, 24, 25}; volatile uint8_t current_self_drive_pin = 0; @@ -64,17 +55,18 @@ uint8_t mapToMidi(uint8_t active_key_group, uint8_t key) { // Check if any of the array pins fell since last time int8_t getActiveKeyGroup() { + uint8_t active_groups = 0; + int8_t last_active_key_group = -1; for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) { // Update status - group_pins[i].update(); - // Check if the pin fell or is low - // ! inverted - if (group_pins[i].fell()) return i; + if (digitalReadFast(group_pins[i])==LOW){ + last_active_key_group = (int8_t) i; + active_groups++; + } } - - // If none fell we should have enough time to see which one is low - for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) { - if (group_pins[i].read() == LOW) return i; + + if (active_groups==1){ + return last_active_key_group; } // Default return @@ -105,7 +97,7 @@ FASTRUN void powerStateChanged() { void setup() { // Set all in- and outputs for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) { - pinMode(group_pins[i].getPin(), INPUT); + pinMode(group_pins[i], INPUT); pinMode(self_drive_pins[i], INPUT); } for (uint8_t i = 0; i < KEY_PINS; i++) { @@ -134,23 +126,23 @@ void loop() { // ! inverted if (value == LOW) { // Check if the key is not already pressed - if (keys_pressed[active_key_group * 6 + i] == 0) { + if (keys_pressed[active_key_group * 6 + i] >= DEBOUNCE_TIMES) { // Send MIDI message usbMIDI.sendNoteOn(mapToMidi(active_key_group, i), 127, 1); - // Set the entry in the array - keys_pressed[active_key_group * 6 + i] = 1; } + // Set the entry in the array + keys_pressed[active_key_group * 6 + i] += keys_pressed[active_key_group * 6 + i] < 0xFF? 1:0; } else { // Check if the key is not already released - if (keys_pressed[active_key_group * 6 + i] == 1) { + if (keys_pressed[active_key_group * 6 + i] < DEBOUNCE_TIMES) { // Send MIDI message usbMIDI.sendNoteOff(mapToMidi(active_key_group, i), 0, 1); - // Set the entry in the array - keys_pressed[active_key_group * 6 + i] = 0; } + // Set the entry in the array + keys_pressed[active_key_group * 6 + i] = 0; } } - } + } // MIDI Controllers should discard incoming MIDI messages. while (usbMIDI.read()) { From 0c13d4da751acca06981ebdad956ced97142c178 Mon Sep 17 00:00:00 2001 From: Oliver Parczyk Date: Sat, 16 Dec 2023 11:55:02 +0100 Subject: [PATCH 3/7] Fix constantly playing note out of range --- src/main.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 20976f8..0d8741a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -121,6 +121,12 @@ void loop() { uint8_t value; for (uint8_t i = 0; i < KEY_PINS; i++) { + // due to the circuitry, there is one phantom note above + // the highest key constantly 'playing' + // but we don't need to scan that far anyway + if (active_key_group == KEY_GROUP_NUM-1 && i>0){ + break; + } value = digitalReadFast(key_pins[i]); // If the key is pressed, we send a MIDI message and set the entry in the array // ! inverted From 54d685f62b2b985e81ee4c65625cb429c19738c8 Mon Sep 17 00:00:00 2001 From: Oliver Parczyk Date: Sat, 16 Dec 2023 11:56:37 +0100 Subject: [PATCH 4/7] Fix wrong order of keys --- src/main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0d8741a..402d629 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,15 +27,15 @@ IntervalTimer self_drive_timer = IntervalTimer(); // Map the current array and pressed key to a MIDI note uint8_t mapToMidi(uint8_t active_key_group, uint8_t key) { uint8_t offset = (active_key_group >> 1) * 12; - // TODO: maybe we have to switch the notes and array offsets + // case 3 and case 4 are swapped on purpose to reflect circuitry // Uneven offset are the upper octave, even the lower if (active_key_group & 1) { switch (key) { case 0: return offset + 42; // F#2 + offset case 1: return offset + 43; // G2 + offset case 2: return offset + 44; // G#2 + offset - case 3: return offset + 45; // A2 + offset - case 4: return offset + 46; // A#2 + offset + case 4: return offset + 45; // A2 + offset + case 3: return offset + 46; // A#2 + offset case 5: return offset + 47; // B2 + offset } } else { @@ -43,8 +43,8 @@ uint8_t mapToMidi(uint8_t active_key_group, uint8_t key) { case 0: return offset + 36; // C2 + offset case 1: return offset + 37; // C#2 + offset case 2: return offset + 38; // D2 + offset - case 3: return offset + 39; // D#2 + offset - case 4: return offset + 40; // E2 + offset + case 4: return offset + 39; // D#2 + offset + case 3: return offset + 40; // E2 + offset case 5: return offset + 41; // F2 + offset } } From 4c1658a3c6354e519d824c5e334a789a68bb64b2 Mon Sep 17 00:00:00 2001 From: Oliver Parczyk Date: Sat, 16 Dec 2023 11:57:52 +0100 Subject: [PATCH 5/7] Fix pinmode of self driving pins --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 402d629..319a2be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -98,7 +98,7 @@ void setup() { // Set all in- and outputs for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) { pinMode(group_pins[i], INPUT); - pinMode(self_drive_pins[i], INPUT); + pinMode(self_drive_pins[i], OUTPUT); } for (uint8_t i = 0; i < KEY_PINS; i++) { pinMode(key_pins[i], INPUT); From 7bf222228ec8d0cad6b0dcdeccbb57836b934f1d Mon Sep 17 00:00:00 2001 From: Oliver Parczyk Date: Sat, 16 Dec 2023 12:03:25 +0100 Subject: [PATCH 6/7] Fix self driving mode There was no need to have a timer do the key group switching routine. Not only would that have to be syncronized to the main loop somehow (or run very slowly), it's also quite an overhead to keep track of. Just switching to the next key group after we're done scanning the current one, syncronously, works far better (and faster!). --- src/main.cpp | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 319a2be..86a1c87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,8 +11,6 @@ #define POWER_SUPPLY_CHECK_PIN 13 -#define SELF_DRIVE_INTERVAL 100 - const uint8_t group_pins[KEY_GROUP_NUM] {14, 15, 16, 17, 18, 19, 20, 21, 22}; // not KEY0%6..not KEY5%6 @@ -21,8 +19,7 @@ const uint8_t key_pins[KEY_PINS] {2, 3, 4, 5, 6, 7}; uint8_t keys_pressed[NUMBER_OF_KEYS]; // K1, K2, K3, K4, K5, K12, K13, K14, K15 const uint8_t self_drive_pins[KEY_GROUP_NUM] {8, 9, 10, 11, 12, 26, 23, 24, 25}; -volatile uint8_t current_self_drive_pin = 0; -IntervalTimer self_drive_timer = IntervalTimer(); +uint8_t current_self_drive_pin = 0; // Map the current array and pressed key to a MIDI note uint8_t mapToMidi(uint8_t active_key_group, uint8_t key) { @@ -76,23 +73,12 @@ int8_t getActiveKeyGroup() { // Set the next self drive pin FASTRUN void nextSelfDrivePin() { // Set the current pin to high + digitalWriteFast(self_drive_pins[current_self_drive_pin!=0?current_self_drive_pin-1:KEY_GROUP_NUM-1], LOW); digitalWriteFast(self_drive_pins[current_self_drive_pin], HIGH); // Set the next pin current_self_drive_pin = (current_self_drive_pin + 1) % KEY_GROUP_NUM; } -// Interrupt for power supply check -FASTRUN void powerStateChanged() { - uint8_t state = digitalReadFast(POWER_SUPPLY_CHECK_PIN); - // ! inverted - if (state == LOW) { - current_self_drive_pin = 0; - self_drive_timer.begin(nextSelfDrivePin, SELF_DRIVE_INTERVAL); - } else { - self_drive_timer.end(); - } -} - // Initial start function void setup() { // Set all in- and outputs @@ -104,10 +90,6 @@ void setup() { pinMode(key_pins[i], INPUT); } pinMode(POWER_SUPPLY_CHECK_PIN, INPUT); - // Manual call, so we can set the initial state - powerStateChanged(); - // Setup interrupt for power supply - attachInterrupt(POWER_SUPPLY_CHECK_PIN, []() { while (true); }, CHANGE); } // Main loop @@ -153,4 +135,9 @@ void loop() { // MIDI Controllers should discard incoming MIDI messages. while (usbMIDI.read()) { } + + // switch to next key group, if self powered + if (digitalReadFast(POWER_SUPPLY_CHECK_PIN) == LOW) { + nextSelfDrivePin(); + } } \ No newline at end of file From 262ecbd928ca25c55cf0a10e9e2fc76f3469563d Mon Sep 17 00:00:00 2001 From: Daniel Kluge Date: Sat, 16 Dec 2023 12:58:34 +0100 Subject: [PATCH 7/7] Formatting --- src/main.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 86a1c87..3b5642e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,7 +56,7 @@ int8_t getActiveKeyGroup() { int8_t last_active_key_group = -1; for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) { // Update status - if (digitalReadFast(group_pins[i])==LOW){ + if (digitalReadFast(group_pins[i]) == LOW){ last_active_key_group = (int8_t) i; active_groups++; } @@ -73,7 +73,7 @@ int8_t getActiveKeyGroup() { // Set the next self drive pin FASTRUN void nextSelfDrivePin() { // Set the current pin to high - digitalWriteFast(self_drive_pins[current_self_drive_pin!=0?current_self_drive_pin-1:KEY_GROUP_NUM-1], LOW); + digitalWriteFast(self_drive_pins[current_self_drive_pin != 0 ? current_self_drive_pin - 1 : KEY_GROUP_NUM - 1], LOW); digitalWriteFast(self_drive_pins[current_self_drive_pin], HIGH); // Set the next pin current_self_drive_pin = (current_self_drive_pin + 1) % KEY_GROUP_NUM; @@ -118,14 +118,16 @@ void loop() { // Send MIDI message usbMIDI.sendNoteOn(mapToMidi(active_key_group, i), 127, 1); } + // Set the entry in the array - keys_pressed[active_key_group * 6 + i] += keys_pressed[active_key_group * 6 + i] < 0xFF? 1:0; + keys_pressed[active_key_group * 6 + i] += keys_pressed[active_key_group * 6 + i] < 0xFF ? 1 : 0; } else { // Check if the key is not already released if (keys_pressed[active_key_group * 6 + i] < DEBOUNCE_TIMES) { // Send MIDI message usbMIDI.sendNoteOff(mapToMidi(active_key_group, i), 0, 1); } + // Set the entry in the array keys_pressed[active_key_group * 6 + i] = 0; } @@ -133,8 +135,7 @@ void loop() { } // MIDI Controllers should discard incoming MIDI messages. - while (usbMIDI.read()) { - } + while (usbMIDI.read()) {} // switch to next key group, if self powered if (digitalReadFast(POWER_SUPPLY_CHECK_PIN) == LOW) {