瀏覽代碼

implement button matrix reading

Thomas Buck 7 月之前
父節點
當前提交
7269be8b92
共有 10 個檔案被更改,包括 194 行新增47 行删除
  1. 1
    0
      docs/src/pcb1.md
  2. 1
    0
      docs/src/pcb2.md
  3. 2
    0
      include/buttons.h
  4. 3
    0
      include/lcd.h
  5. 2
    0
      include/main.h
  6. 52
    12
      src/buttons.c
  7. 44
    0
      src/lcd.c
  8. 36
    10
      src/main.c
  9. 15
    6
      src/sequence.c
  10. 38
    19
      src/ui.c

+ 1
- 0
docs/src/pcb1.md 查看文件

@@ -20,6 +20,7 @@ These are all the parts required to assemble the prototype.
20 20
 | U3, U5, U7 | Step-Up Converter Module | [Amazon.de](https://www.amazon.de/Converter-Spannungswandler-LAOMAO-Netzteil-Kompatibel/dp/B0B932BR7V) |
21 21
 | J2 | SSD1306 128x64 0.96" Display | [Amazon.de](https://www.amazon.de/AZDelivery-Display-Arduino-Raspberry-gratis/dp/B01L9GC470) |
22 22
 | S1 | ALPS EC12E24244 | [Reichelt.de](https://www.reichelt.de/drehimpulsegeber-24-impulse-24-rastungen-vertikal-stec12e08-p73923.html?&nbc=1) |
23
+| - | Cap for encoder knob | [Reichelt.de](https://www.reichelt.de/potentiometerknopf-fuer-achse-6-4-5-mm-schwarz-knopf-10-150e-p73960.html) |
23 24
 | D1 - D4 | LED 5mm | [Reichelt.de](https://www.reichelt.de/led-5mm-bedrahtet-rot-450-mcd-90--5603r1c-khb-a-p361958.html?&nbc=1) |
24 25
 | D5 - D8 | 1N5819 Schottky Diode | [Reichelt.de](https://www.reichelt.de/schottkydiode-40-v-1-a-do-41-1n-5819-p41850.html?&nbc=1) |
25 26
 | R1 - R4 | Resistor 1k Ohm | [Reichelt.de](https://www.reichelt.de/widerstand-metallschicht-1-00-kohm-0207-0-6-w-1--metall-1-00k-p11403.html?&nbc=1) |

+ 1
- 0
docs/src/pcb2.md 查看文件

@@ -22,6 +22,7 @@ These are all the parts required to assemble the V2 PCB.
22 22
 | BT1 | Keystone 1042 | [Reichelt.de](https://www.reichelt.de/batteriehalter-fuer-1-18650-keystone-1042-p213369.html?&nbc=1) |
23 23
 | S1 | APEM 5236AB | [Reichelt.de](https://www.reichelt.de/kippschalter-1a-250vac-1x-ein-ein-printanschluss-as-500apc-p4396.html?&nbc=1) |
24 24
 | SW1 | ALPS EC12E24244 | [Reichelt.de](https://www.reichelt.de/drehimpulsegeber-24-impulse-24-rastungen-vertikal-stec12e08-p73923.html?&nbc=1) |
25
+| - | Cap for encoder knob | [Reichelt.de](https://www.reichelt.de/potentiometerknopf-fuer-achse-6-4-5-mm-schwarz-knopf-10-150e-p73960.html) |
25 26
 | SW2 - SW10 | DIP 6x6mm push button | [Reichelt.de](https://www.reichelt.de/kurzhubtaster-printmontage-1-schliesser-6-x-6-x-5-mm-dip-dts-62k-v-p360043.html?&nbc=1) |
26 27
 | D1 - D4 | 1N5819 Schottky Diode | [Reichelt.de](https://www.reichelt.de/schottkydiode-40-v-1-a-do-41-1n-5819-p41850.html?&nbc=1) |
27 28
 | D5 - D12 | LED 5mm | [Reichelt.de](https://www.reichelt.de/led-5mm-bedrahtet-rot-450-mcd-90--5603r1c-khb-a-p361958.html?&nbc=1) |

+ 2
- 0
include/buttons.h 查看文件

@@ -21,6 +21,8 @@
21 21
 
22 22
 #include <stdbool.h>
23 23
 
24
+#define DEBOUNCE_DELAY_MS 50
25
+
24 26
 enum buttons {
25 27
     BTN_A = 0,
26 28
     BTN_B,

+ 3
- 0
include/lcd.h 查看文件

@@ -24,5 +24,8 @@
24 24
 
25 25
 void lcd_init(void);
26 26
 void lcd_draw(const char *mode, const char *val, const char *bat);
27
+void lcd_draw_bye(void);
28
+
29
+void lcd_debug_buttons(void);
27 30
 
28 31
 #endif // __LCD_H__

+ 2
- 0
include/main.h 查看文件

@@ -27,4 +27,6 @@ enum hw_versions {
27 27
 
28 28
 extern enum hw_versions hw_type;
29 29
 
30
+void handle_serial_input(void);
31
+
30 32
 #endif // __MAIN_H__

+ 52
- 12
src/buttons.c 查看文件

@@ -22,8 +22,6 @@
22 22
 #include "main.h"
23 23
 #include "buttons.h"
24 24
 
25
-#define DEBOUNCE_DELAY_MS 50
26
-
27 25
 static const uint gpio_num_proto[NUM_BTNS] = {
28 26
     8, // BTN_A
29 27
     9, // BTN_B
@@ -40,19 +38,32 @@ static const uint gpio_num_proto[NUM_BTNS] = {
40 38
     16, // BTN_CLICK
41 39
 };
42 40
 
41
+#define NUM_ROWS 3
42
+#define NUM_COLS 3
43
+
43 44
 static const uint gpio_num_v2[NUM_BTNS] = {
44
-    1, // BTN_A / COL 0
45
-    4, // BTN_B / COL 1
46
-    5, // BTN_C / COL 2
47
-    0, // BTN_D / ROW 0
48
-    2, // BTN_E / ROW 1
49
-    3, // BTN_F / ROW 2
45
+    // handled as matrix
46
+    0xFF, // BTN_A
47
+    0xFF, // BTN_B
48
+    0xFF, // BTN_C
49
+    0xFF, // BTN_D
50
+    0xFF, // BTN_E
51
+    0xFF, // BTN_F
50 52
     0xFF, // BTN_G
51 53
     0xFF, // BTN_H
52 54
     0xFF, // BTN_REC
55
+
53 56
     20, // BTN_CLICK
54 57
 };
55 58
 
59
+static const uint gpio_rows[NUM_ROWS] = {
60
+    0, 2, 3
61
+};
62
+
63
+static const uint gpio_cols[NUM_COLS] = {
64
+    1, 4, 5
65
+};
66
+
56 67
 struct button_state {
57 68
     uint32_t last_time;
58 69
     bool current_state, last_state;
@@ -60,6 +71,7 @@ struct button_state {
60 71
 
61 72
 static struct button_state buttons[NUM_BTNS];
62 73
 static void (*callback)(enum buttons, bool) = NULL;
74
+static int last_col = 0;
63 75
 
64 76
 void buttons_init(void) {
65 77
     for (uint i = 0; i < NUM_BTNS; i++) {
@@ -82,6 +94,24 @@ void buttons_init(void) {
82 94
         buttons[i].current_state = false;
83 95
         buttons[i].last_state = false;
84 96
     }
97
+
98
+    if (hw_type != HW_V2) {
99
+        return;
100
+    }
101
+
102
+    for (uint i = 0; i < NUM_ROWS; i++) {
103
+        uint n = gpio_rows[i];
104
+        gpio_init(n);
105
+        gpio_set_dir(n, GPIO_IN);
106
+        gpio_pull_up(n);
107
+    }
108
+
109
+    for (uint i = 0; i < NUM_COLS; i++) {
110
+        uint n = gpio_cols[i];
111
+        gpio_init(n);
112
+        gpio_set_dir(n, GPIO_IN);
113
+        gpio_disable_pulls(n);
114
+    }
85 115
 }
86 116
 
87 117
 void buttons_callback(void (*fp)(enum buttons, bool)) {
@@ -109,7 +139,7 @@ static void button_run_single(bool state, uint i) {
109 139
     buttons[i].last_state = state;
110 140
 }
111 141
 
112
-static void buttons_run_proto(void) {
142
+static void button_run_proto(void) {
113 143
     for (uint i = 0; i < NUM_BTNS; i++) {
114 144
         if (gpio_num_proto[i] >= 0xFF) {
115 145
             continue;
@@ -120,12 +150,22 @@ static void buttons_run_proto(void) {
120 150
     }
121 151
 }
122 152
 
153
+static void button_run_matrix(void) {
154
+    gpio_set_dir(gpio_cols[last_col], GPIO_IN);
155
+    last_col = (last_col + 1) % NUM_COLS;
156
+    gpio_set_dir(gpio_cols[last_col], GPIO_OUT);
157
+    gpio_put(gpio_cols[last_col], false);
158
+    sleep_us(2);
159
+    for (uint i = 0; i < NUM_ROWS; i++) {
160
+        button_run_single(!gpio_get(gpio_rows[i]), last_col * NUM_ROWS + i);
161
+    }
162
+}
163
+
123 164
 void buttons_run(void) {
124 165
     if (hw_type == HW_PROTOTYPE) {
125
-        buttons_run_proto();
166
+        button_run_proto();
126 167
     } else if (hw_type == HW_V2) {
127
-        // TODO read matrix
128
-
168
+        button_run_matrix();
129 169
         button_run_single(!gpio_get(gpio_num_v2[BTN_CLICK]), BTN_CLICK);
130 170
     }
131 171
 }

+ 44
- 0
src/lcd.c 查看文件

@@ -23,6 +23,8 @@
23 23
 #include "hardware/i2c.h"
24 24
 
25 25
 #include "ssd1306.h"
26
+
27
+#include "buttons.h"
26 28
 #include "logo.h"
27 29
 #include "main.h"
28 30
 #include "lcd.h"
@@ -36,6 +38,41 @@ static const uint gpio_num_v2[2] = { 16, 17 };
36 38
 #define LCD_ADDR 0x3C
37 39
 
38 40
 static ssd1306_t disp;
41
+static bool buttons[NUM_BTNS] = {0};
42
+static bool changed = true;
43
+
44
+static void lcd_debug_buttons_callback(enum buttons btn, bool v) {
45
+    buttons[btn] = v;
46
+    changed = true;
47
+}
48
+
49
+void lcd_debug_buttons(void) {
50
+    buttons_callback(lcd_debug_buttons_callback);
51
+    while (1) {
52
+        buttons_run();
53
+        handle_serial_input();
54
+        if (changed) {
55
+            changed = false;
56
+            ssd1306_clear(&disp);
57
+            ssd1306_draw_string(&disp, 0, 0, 3, "Buttons");
58
+            for (uint i = 0; i < NUM_BTNS; i++) {
59
+                ssd1306_draw_char(&disp,
60
+                                    i * 12, LCD_HEIGHT - 20 - 16 - 1,
61
+                                    2, '0' + i);
62
+                if (buttons[i]) {
63
+                    ssd1306_draw_square(&disp,
64
+                                        i * 12, LCD_HEIGHT - 20 - 1,
65
+                                        10, 20);
66
+                } else {
67
+                    ssd1306_draw_empty_square(&disp,
68
+                                                i * 12, LCD_HEIGHT - 20 - 1,
69
+                                                10, 20);
70
+                }
71
+            }
72
+            ssd1306_show(&disp);
73
+        }
74
+    }
75
+}
39 76
 
40 77
 void lcd_init(void) {
41 78
     if (hw_type == HW_PROTOTYPE) {
@@ -58,6 +95,7 @@ void lcd_init(void) {
58 95
         ssd1306_init(&disp, LCD_WIDTH, LCD_HEIGHT, LCD_ADDR, gpio_i2c_v2);
59 96
     }
60 97
 
98
+    // show logo
61 99
     ssd1306_clear(&disp);
62 100
     for (uint y = 0; y < LOGO_HEIGHT; y++) {
63 101
         for (uint x = 0; x < LOGO_WIDTH; x++) {
@@ -76,6 +114,12 @@ void lcd_draw(const char *mode, const char *val, const char *bat) {
76 114
     ssd1306_draw_string(&disp, 0, 0, 2, mode);
77 115
     ssd1306_draw_string(&disp, 0, 20, 4, val);
78 116
     ssd1306_draw_string(&disp, 0, LCD_HEIGHT - 1 - 10, 1, bat);
117
+    ssd1306_show(&disp);
118
+}
79 119
 
120
+void lcd_draw_bye(void) {
121
+    ssd1306_clear(&disp);
122
+    ssd1306_draw_string(&disp, 0, 0, 3, "Boot");
123
+    ssd1306_draw_string(&disp, 0, LCD_HEIGHT / 2, 3, "loader");
80 124
     ssd1306_show(&disp);
81 125
 }

+ 36
- 10
src/main.c 查看文件

@@ -35,9 +35,18 @@
35 35
 #define LOGO_INIT_MS 1500
36 36
 
37 37
 static const uint gpio_hw_detect = 21;
38
+
38 39
 enum hw_versions hw_type = HW_UNKNOWN;
39 40
 
41
+static bool debug_buttons[NUM_BTNS] = {0};
42
+
43
+static void debug_buttons_callback(enum buttons btn, bool v) {
44
+    debug_buttons[btn] = v;
45
+}
46
+
40 47
 static void reset_to_bootloader(void) {
48
+    lcd_draw_bye();
49
+
41 50
 #ifdef PICO_DEFAULT_LED_PIN
42 51
     reset_usb_boot(1 << PICO_DEFAULT_LED_PIN, 0);
43 52
 #else // ! PICO_DEFAULT_LED_PIN
@@ -45,6 +54,15 @@ static void reset_to_bootloader(void) {
45 54
 #endif // PICO_DEFAULT_LED_PIN
46 55
 }
47 56
 
57
+void handle_serial_input(void) {
58
+    int c = getchar_timeout_us(0);
59
+    if (c == 0x18) {
60
+        reset_to_bootloader();
61
+    } else if (c != PICO_ERROR_TIMEOUT) {
62
+        printf("%c", c);
63
+    }
64
+}
65
+
48 66
 int main(void) {
49 67
     stdio_init_all();
50 68
 
@@ -63,10 +81,23 @@ int main(void) {
63 81
     lcd_init();
64 82
     led_init();
65 83
 
66
-    // show splash for a bit and animate LEDs
67
-    for (uint i = 0; i < LED_COUNT; i++) {
68
-        led_set(i, true);
69
-        sleep_ms(LOGO_INIT_MS / LED_COUNT);
84
+    // read out button state for debug options
85
+    buttons_callback(debug_buttons_callback);
86
+    for (uint i = 0; i < (DEBOUNCE_DELAY_MS + 5); i++) {
87
+        buttons_run();
88
+        handle_serial_input();
89
+        sleep_ms(1);
90
+    }
91
+
92
+    if (debug_buttons[BTN_REC]) {
93
+        lcd_debug_buttons();
94
+    } else if (!debug_buttons[BTN_H]) {
95
+        // show splash for a bit and animate LEDs
96
+        for (uint i = 0; i < LED_COUNT; i++) {
97
+            handle_serial_input();
98
+            led_set(i, true);
99
+            sleep_ms(LOGO_INIT_MS / LED_COUNT);
100
+        }
70 101
     }
71 102
 
72 103
     // turn off LEDs at end of init
@@ -96,12 +127,7 @@ int main(void) {
96 127
             last_epos = epos;
97 128
         }
98 129
 
99
-        int c = getchar_timeout_us(0);
100
-        if (c == 0x18) {
101
-            reset_to_bootloader();
102
-        } else if (c != PICO_ERROR_TIMEOUT) {
103
-            printf("%c", c);
104
-        }
130
+        handle_serial_input();
105 131
     }
106 132
 
107 133
     return 0;

+ 15
- 6
src/sequence.c 查看文件

@@ -101,21 +101,27 @@ static bool sequence_get(uint32_t beat, enum channels ch) {
101 101
 
102 102
 void sequence_handle_button_loopstation(enum buttons btn, bool rec) {
103 103
     switch (btn) {
104
-        case BTN_A: {
104
+        case BTN_A:
105
+        case BTN_E: {
105 106
             pulse_trigger_out(0, channel_times[0]);
106 107
             pulse_trigger_led(0, channel_times[0]);
108
+            pulse_trigger_led(4, channel_times[0]);
107 109
             break;
108 110
         }
109 111
 
110
-        case BTN_B: {
112
+        case BTN_B:
113
+        case BTN_F: {
111 114
             pulse_trigger_out(1, channel_times[1]);
112 115
             pulse_trigger_led(1, channel_times[1]);
116
+            pulse_trigger_led(5, channel_times[1]);
113 117
             break;
114 118
         }
115 119
 
116
-        case BTN_C: {
120
+        case BTN_C:
121
+        case BTN_G: {
117 122
             pulse_trigger_out(2, channel_times[2]);
118 123
             pulse_trigger_led(2, channel_times[2]);
124
+            pulse_trigger_led(6, channel_times[2]);
119 125
             break;
120 126
         }
121 127
 
@@ -126,17 +132,20 @@ void sequence_handle_button_loopstation(enum buttons btn, bool rec) {
126 132
 
127 133
     if (rec) {
128 134
         switch (btn) {
129
-            case BTN_A: {
135
+            case BTN_A:
136
+            case BTN_E: {
130 137
                 sequence_set(last_i, CH_KICK, true);
131 138
                 break;
132 139
             }
133 140
 
134
-            case BTN_B: {
141
+            case BTN_B:
142
+            case BTN_F: {
135 143
                 sequence_set(last_i, CH_SNARE, true);
136 144
                 break;
137 145
             }
138 146
 
139
-            case BTN_C: {
147
+            case BTN_C:
148
+            case BTN_G: {
140 149
                 sequence_set(last_i, CH_HIHAT, true);
141 150
                 break;
142 151
             }

+ 38
- 19
src/ui.c 查看文件

@@ -23,6 +23,7 @@
23 23
 #include "adc.h"
24 24
 #include "buttons.h"
25 25
 #include "lcd.h"
26
+#include "led.h"
26 27
 #include "sequence.h"
27 28
 #include "ui.h"
28 29
 
@@ -104,14 +105,19 @@ static void ui_buttons_loopstation(enum buttons btn, bool val) {
104 105
     switch (btn) {
105 106
         case BTN_A:
106 107
         case BTN_B:
107
-        case BTN_C: {
108
+        case BTN_C:
109
+        case BTN_E:
110
+        case BTN_F:
111
+        case BTN_G: {
108 112
             if (val) {
109 113
                 sequence_handle_button_loopstation(btn, rec_held_down);
110 114
             }
111 115
             break;
112 116
         }
113 117
 
114
-        case BTN_REC: {
118
+        case BTN_REC:
119
+        case BTN_D:
120
+        case BTN_H: {
115 121
             rec_held_down = val;
116 122
             sequence_looptime(!val);
117 123
             break;
@@ -129,6 +135,11 @@ static void ui_buttons_drummachine(enum buttons btn, bool val) {
129 135
         case BTN_A:
130 136
         case BTN_B:
131 137
         case BTN_C:
138
+        case BTN_D:
139
+        case BTN_E:
140
+        case BTN_F:
141
+        case BTN_G:
142
+        case BTN_H:
132 143
         case BTN_REC: {
133 144
             if (val) {
134 145
                 sequence_handle_button_drummachine(btn);
@@ -143,27 +154,14 @@ static void ui_buttons_drummachine(enum buttons btn, bool val) {
143 154
     }
144 155
 }
145 156
 
146
-
147
-#include "pulse.h"
148
-
149
-
150 157
 static void ui_buttons(enum buttons btn, bool val) {
151 158
     switch (btn) {
152 159
         case BTN_CLICK: {
153 160
             if (val) {
154
-
155
-
156
-
157
-                pulse_trigger_out(0, 42);
158
-                pulse_trigger_led(0, 42);
159
-
160
-
161
-
162 161
                 ui_mode = (ui_mode + 1) % UI_NUM_MODES;
163 162
 
164
-                // allow other ui mdoes only in drumkit mode
165
-                if (machine_mode == MODE_LOOPSTATION)
166
-                {
163
+                // allow other ui modes only in drumkit mode
164
+                if (machine_mode == MODE_LOOPSTATION) {
167 165
                     ui_mode = 0;
168 166
                 }
169 167
 
@@ -215,12 +213,27 @@ void ui_encoder(int32_t val) {
215 213
             while (tmp >= MACHINE_NUM_MODES) {
216 214
                 tmp -= MACHINE_NUM_MODES;
217 215
             }
216
+
217
+            enum machine_modes prev_mode = machine_mode;
218 218
             machine_mode = tmp;
219 219
 
220 220
             printf("mode add %"PRIi32" now %d\n", val, machine_mode);
221 221
 
222
-            // reset sequence
223
-            sequence_init();
222
+            if (prev_mode != machine_mode) {
223
+                // reset sequence
224
+                sequence_init();
225
+
226
+                // turn off all LEDs
227
+                for (uint i = 0; i < LED_COUNT; i++) {
228
+                    led_set(i, false);
229
+                }
230
+
231
+                // enable static LEDs in loopstation mode
232
+                if (machine_mode == MODE_LOOPSTATION) {
233
+                    led_set(NUM_CHANNELS, true);
234
+                    led_set(NUM_CHANNELS + 4, true);
235
+                }
236
+            }
224 237
             break;
225 238
         }
226 239
 
@@ -247,6 +260,12 @@ void ui_encoder(int32_t val) {
247 260
 
248 261
 void ui_init(void) {
249 262
     buttons_callback(ui_buttons);
263
+
264
+    // enable static LEDs in loopstation mode
265
+    machine_mode = MODE_LOOPSTATION;
266
+    led_set(NUM_CHANNELS, true);
267
+    led_set(NUM_CHANNELS + 4, true);
268
+
250 269
     ui_redraw();
251 270
 }
252 271
 

Loading…
取消
儲存