Browse Source

work on firmware

Thomas Buck 8 months ago
parent
commit
01cff091a6
14 changed files with 189 additions and 17 deletions
  1. 1
    0
      CMakeLists.txt
  2. 1
    1
      README.md
  3. 25
    0
      include/adc.h
  4. 0
    1
      include/buttons.h
  5. 0
    1
      include/encoder.h
  6. 1
    0
      include/lcd.h
  7. 12
    0
      include/sequence.h
  8. 1
    0
      include/ui.h
  9. 47
    0
      src/adc.c
  10. 4
    1
      src/encoder.c
  11. 10
    0
      src/lcd.c
  12. 3
    0
      src/main.c
  13. 26
    1
      src/sequence.c
  14. 58
    12
      src/ui.c

+ 1
- 0
CMakeLists.txt View File

30
 add_executable(drumkit)
30
 add_executable(drumkit)
31
 
31
 
32
 target_sources(drumkit PUBLIC
32
 target_sources(drumkit PUBLIC
33
+    src/adc.c
33
     src/buttons.c
34
     src/buttons.c
34
     src/encoder.c
35
     src/encoder.c
35
     src/lcd.c
36
     src/lcd.c

+ 1
- 1
README.md View File

53
 
53
 
54
 The code in `src/encoder.c` is derived from [mathertel/RotaryEncoder](https://github.com/mathertel/RotaryEncoder) and therefore licensed as BSD 3-clause.
54
 The code in `src/encoder.c` is derived from [mathertel/RotaryEncoder](https://github.com/mathertel/RotaryEncoder) and therefore licensed as BSD 3-clause.
55
 
55
 
56
-The PCB design uses `Mini360_step_down_converter` library from [rayvburn/KiCad](https://github.com/rayvburn/KiCad/tree/master/Mini360_step_down_converter).
56
+~~The PCB design uses `Mini360_step_down_converter` library from [rayvburn/KiCad](https://github.com/rayvburn/KiCad/tree/master/Mini360_step_down_converter).~~
57
 
57
 
58
     This program is free software: you can redistribute it and/or modify
58
     This program is free software: you can redistribute it and/or modify
59
     it under the terms of the GNU General Public License as published by
59
     it under the terms of the GNU General Public License as published by

+ 25
- 0
include/adc.h View File

1
+/*
2
+ * adc.h
3
+ *
4
+ * Copyright (c) 2022 - 2023 Thomas Buck (thomas@xythobuz.de)
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * See <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+#ifndef __ADC_H__
20
+#define __ADC_H__
21
+
22
+void bat_init(void);
23
+float bat_get(void);
24
+
25
+#endif // __ADC_H__

+ 0
- 1
include/buttons.h View File

35
 void buttons_run(void);
35
 void buttons_run(void);
36
 
36
 
37
 #endif // __BUTTONS_H__
37
 #endif // __BUTTONS_H__
38
-

+ 0
- 1
include/encoder.h View File

26
 void encoder_run(void);
26
 void encoder_run(void);
27
 
27
 
28
 #endif // __ENCODER_H__
28
 #endif // __ENCODER_H__
29
-

+ 1
- 0
include/lcd.h View File

23
 #define LCD_HEIGHT 64
23
 #define LCD_HEIGHT 64
24
 
24
 
25
 void lcd_init(void);
25
 void lcd_init(void);
26
+void lcd_draw(const char *mode, const char *val, const char *bat);
26
 
27
 
27
 #endif // __LCD_H__
28
 #endif // __LCD_H__

+ 12
- 0
include/sequence.h View File

36
 
36
 
37
 #define CH_GPIO_TIMINGS { 42, 42, 42 } // in milliseconds
37
 #define CH_GPIO_TIMINGS { 42, 42, 42 } // in milliseconds
38
 
38
 
39
+#define MAX_BEATS 32
40
+#define MAX_BANKS (MAX_BEATS / NUM_BTNS)
41
+
39
 void sequence_init(void);
42
 void sequence_init(void);
43
+
40
 void sequence_set_bpm(uint32_t new_bpm);
44
 void sequence_set_bpm(uint32_t new_bpm);
45
+uint32_t sequence_get_bpm(void);
46
+
41
 void sequence_set_beats(uint32_t new_beats);
47
 void sequence_set_beats(uint32_t new_beats);
48
+uint32_t sequence_get_beats(void);
49
+
50
+void sequence_set_bank(uint32_t new_bank);
51
+uint32_t sequence_get_bank(void);
52
+
42
 void sequence_handle_button_loopstation(enum buttons btn, bool rec);
53
 void sequence_handle_button_loopstation(enum buttons btn, bool rec);
43
 void sequence_handle_button_drummachine(enum buttons btn);
54
 void sequence_handle_button_drummachine(enum buttons btn);
55
+
44
 void sequence_run(void);
56
 void sequence_run(void);
45
 
57
 
46
 #endif // __SEQUENCE_H__
58
 #endif // __SEQUENCE_H__

+ 1
- 0
include/ui.h View File

39
 
39
 
40
 void ui_init(void);
40
 void ui_init(void);
41
 void ui_encoder(int32_t val);
41
 void ui_encoder(int32_t val);
42
+void ui_run(void);
42
 
43
 
43
 #endif // __UI_H__
44
 #endif // __UI_H__

+ 47
- 0
src/adc.c View File

1
+/*
2
+ * adc.c
3
+ *
4
+ * Copyright (c) 2024 Thomas Buck (thomas@xythobuz.de)
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * See <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+#include <stdio.h>
20
+#include "pico/stdlib.h"
21
+#include "hardware/adc.h"
22
+
23
+#include "adc.h"
24
+
25
+#define ADC_NUM 2
26
+#define ADC_PIN (26 + ADC_NUM)
27
+
28
+#define ADC_VREF 3.3
29
+#define ADC_RANGE (1 << 12)
30
+#define ADC_CONVERT (ADC_VREF / (ADC_RANGE - 1))
31
+
32
+#define BAT_R1 10000.0f
33
+#define BAT_R2 18000.0f
34
+
35
+void bat_init(void) {
36
+    adc_init();
37
+    adc_gpio_init( ADC_PIN);
38
+    adc_select_input( ADC_NUM);
39
+}
40
+
41
+float bat_get(void) {
42
+    float v_adc = adc_read() * ADC_CONVERT;
43
+
44
+    // Vadc = Vbat * R2 / (R1 + R2)
45
+    float v_bat = v_adc / (BAT_R2 / (BAT_R1 + BAT_R2));
46
+    return v_bat;
47
+}

+ 4
- 1
src/encoder.c View File

22
 #define FOUR0 2 // 4 steps, Latch at position 0 (reverse wirings)
22
 #define FOUR0 2 // 4 steps, Latch at position 0 (reverse wirings)
23
 #define TWO03 3 // 2 steps, Latch at position 0 and 3
23
 #define TWO03 3 // 2 steps, Latch at position 0 and 3
24
 
24
 
25
-#define ENCODER_MODE TWO03
25
+#define ENCODER_MODE FOUR3
26
 
26
 
27
 static const uint gpio_num[2] = {
27
 static const uint gpio_num[2] = {
28
     17, 18
28
     17, 18
70
             if (thisState == LATCH3) {
70
             if (thisState == LATCH3) {
71
                 // The hardware has 4 steps with a latch on the input state 3
71
                 // The hardware has 4 steps with a latch on the input state 3
72
                 positionExt = position >> 2;
72
                 positionExt = position >> 2;
73
+                positionExt = -positionExt;
73
             }
74
             }
74
             break;
75
             break;
75
 
76
 
77
             if (thisState == LATCH0) {
78
             if (thisState == LATCH0) {
78
                 // The hardware has 4 steps with a latch on the input state 0
79
                 // The hardware has 4 steps with a latch on the input state 0
79
                 positionExt = position >> 2;
80
                 positionExt = position >> 2;
81
+                positionExt = -positionExt;
80
             }
82
             }
81
             break;
83
             break;
82
 
84
 
84
             if ((thisState == LATCH0) || (thisState == LATCH3)) {
86
             if ((thisState == LATCH0) || (thisState == LATCH3)) {
85
                 // The hardware has 2 steps with a latch on the input state 0 and 3
87
                 // The hardware has 2 steps with a latch on the input state 0 and 3
86
                 positionExt = position >> 1;
88
                 positionExt = position >> 1;
89
+                positionExt = -positionExt;
87
             }
90
             }
88
             break;
91
             break;
89
         }
92
         }

+ 10
- 0
src/lcd.c View File

40
 
40
 
41
     disp.external_vcc = false;
41
     disp.external_vcc = false;
42
     ssd1306_init(&disp, LCD_WIDTH, LCD_HEIGHT, LCD_ADDR, LCD_I2C);
42
     ssd1306_init(&disp, LCD_WIDTH, LCD_HEIGHT, LCD_ADDR, LCD_I2C);
43
+    ssd1306_clear(&disp);
44
+}
45
+
46
+void lcd_draw(const char *mode, const char *val, const char *bat) {
47
+    ssd1306_clear(&disp);
48
+    ssd1306_draw_string(&disp, 0, 0, 2, mode);
49
+    ssd1306_draw_string(&disp, 0, 20, 4, val);
50
+    ssd1306_draw_string(&disp, 0, LCD_HEIGHT - 1 - 10, 1, bat);
51
+
52
+    ssd1306_show(&disp);
43
 }
53
 }

+ 3
- 0
src/main.c View File

20
 #include "pico/stdlib.h"
20
 #include "pico/stdlib.h"
21
 #include "hardware/watchdog.h"
21
 #include "hardware/watchdog.h"
22
 
22
 
23
+#include "adc.h"
23
 #include "buttons.h"
24
 #include "buttons.h"
24
 #include "encoder.h"
25
 #include "encoder.h"
25
 #include "lcd.h"
26
 #include "lcd.h"
34
 int main(void) {
35
 int main(void) {
35
     watchdog_enable(WATCHDOG_PERIOD_MS, 1);
36
     watchdog_enable(WATCHDOG_PERIOD_MS, 1);
36
     stdio_init_all();
37
     stdio_init_all();
38
+    bat_init();
37
     buttons_init();
39
     buttons_init();
38
     encoder_init();
40
     encoder_init();
39
     lcd_init();
41
     lcd_init();
50
         encoder_run();
52
         encoder_run();
51
         sequence_run();
53
         sequence_run();
52
         pulse_run();
54
         pulse_run();
55
+        ui_run();
53
 
56
 
54
         int32_t epos = encoder_pos();
57
         int32_t epos = encoder_pos();
55
         if (epos != last_epos) {
58
         if (epos != last_epos) {

+ 26
- 1
src/sequence.c View File

23
 #include "pulse.h"
23
 #include "pulse.h"
24
 #include "sequence.h"
24
 #include "sequence.h"
25
 
25
 
26
-#define MAX_BEATS 32
27
 static const uint32_t channel_times[NUM_CHANNELS] = CH_GPIO_TIMINGS;
26
 static const uint32_t channel_times[NUM_CHANNELS] = CH_GPIO_TIMINGS;
28
 
27
 
29
 static uint32_t ms_per_beat = 500;
28
 static uint32_t ms_per_beat = 500;
30
 static uint32_t beats = 16;
29
 static uint32_t beats = 16;
31
 static uint32_t last_t = 0;
30
 static uint32_t last_t = 0;
32
 static uint32_t last_i = 0;
31
 static uint32_t last_i = 0;
32
+static uint32_t bank = 0;
33
 
33
 
34
 static enum channels sequence[MAX_BEATS] = {0};
34
 static enum channels sequence[MAX_BEATS] = {0};
35
 
35
 
46
     ms_per_beat = 60000 / new_bpm;
46
     ms_per_beat = 60000 / new_bpm;
47
 }
47
 }
48
 
48
 
49
+uint32_t sequence_get_bpm(void) {
50
+    return 60000 / ms_per_beat;
51
+}
52
+
49
 void sequence_set_beats(uint32_t new_beats) {
53
 void sequence_set_beats(uint32_t new_beats) {
50
     beats = (new_beats <= MAX_BEATS) ? new_beats : MAX_BEATS;
54
     beats = (new_beats <= MAX_BEATS) ? new_beats : MAX_BEATS;
55
+
56
+    uint32_t max_banks_currently = (beats + (NUM_BTNS - 1)) / NUM_BTNS;
57
+    bank = (bank < max_banks_currently) ? bank : max_banks_currently;
58
+}
59
+
60
+uint32_t sequence_get_beats(void) {
61
+    return beats;
62
+}
63
+
64
+void sequence_set_bank(uint32_t new_bank) {
65
+    uint32_t b = (new_bank < MAX_BANKS) ? new_bank : MAX_BANKS;
66
+
67
+    uint32_t max_banks_currently = (beats + (NUM_BTNS - 1)) / NUM_BTNS;
68
+    bank = (b < max_banks_currently) ? b : max_banks_currently;
69
+}
70
+
71
+uint32_t sequence_get_bank(void) {
72
+    return bank;
51
 }
73
 }
52
 
74
 
53
 static void sequence_set(uint32_t beat, enum channels ch, bool value) {
75
 static void sequence_set(uint32_t beat, enum channels ch, bool value) {
123
 
145
 
124
     switch (btn) {
146
     switch (btn) {
125
         case BTN_A: {
147
         case BTN_A: {
148
+            // TODO kick is wrong here
126
             bool val = !sequence_get(beat, CH_KICK);
149
             bool val = !sequence_get(beat, CH_KICK);
127
             sequence_set(beat, CH_KICK, val);
150
             sequence_set(beat, CH_KICK, val);
128
             break;
151
             break;
129
         }
152
         }
130
 
153
 
131
         case BTN_B: {
154
         case BTN_B: {
155
+            // TODO snare is wrong here
132
             bool val = !sequence_get(beat, CH_SNARE);
156
             bool val = !sequence_get(beat, CH_SNARE);
133
             sequence_set(beat, CH_SNARE, val);
157
             sequence_set(beat, CH_SNARE, val);
134
             break;
158
             break;
135
         }
159
         }
136
 
160
 
137
         case BTN_C: {
161
         case BTN_C: {
162
+            // TODO hihat is wrong here
138
             bool val = !sequence_get(beat, CH_HIHAT);
163
             bool val = !sequence_get(beat, CH_HIHAT);
139
             sequence_set(beat, CH_HIHAT, val);
164
             sequence_set(beat, CH_HIHAT, val);
140
             break;
165
             break;

+ 58
- 12
src/ui.c View File

17
  */
17
  */
18
 
18
 
19
 #include <stdio.h>
19
 #include <stdio.h>
20
+#include <inttypes.h>
20
 #include "pico/stdlib.h"
21
 #include "pico/stdlib.h"
21
 
22
 
23
+#include "adc.h"
22
 #include "buttons.h"
24
 #include "buttons.h"
25
+#include "lcd.h"
23
 #include "sequence.h"
26
 #include "sequence.h"
24
 #include "ui.h"
27
 #include "ui.h"
25
 
28
 
29
+#define REDRAW_MS 2000
30
+
26
 static bool rec_held_down = false;
31
 static bool rec_held_down = false;
27
 static enum ui_modes ui_mode = 0;
32
 static enum ui_modes ui_mode = 0;
28
 static enum machine_modes machine_mode = 0;
33
 static enum machine_modes machine_mode = 0;
34
+static uint32_t last_redraw = 0;
29
 
35
 
30
 static void ui_redraw(void) {
36
 static void ui_redraw(void) {
37
+    char mode[64] = {0};
38
+    char val[64] = {0};
39
+    char bat[64] = {0};
40
+
31
     switch (ui_mode) {
41
     switch (ui_mode) {
32
         case UI_BPM: {
42
         case UI_BPM: {
33
-            // TODO
43
+            snprintf(mode, sizeof(mode) - 1, "BPM:");
44
+            snprintf(val, sizeof(val) - 1, "%"PRIu32, sequence_get_bpm());
34
             break;
45
             break;
35
         }
46
         }
36
 
47
 
37
         case UI_MODE: {
48
         case UI_MODE: {
38
-            // TODO
49
+            snprintf(mode, sizeof(mode) - 1, "Mode:");
50
+            switch (machine_mode) {
51
+                case MODE_LOOPSTATION: {
52
+                    snprintf(val, sizeof(val) - 1, "Loop");
53
+                    break;
54
+                }
55
+
56
+                case MODE_DRUMMACHINE: {
57
+                    snprintf(val, sizeof(val) - 1, "Drum");
58
+                    break;
59
+                }
60
+
61
+                default: {
62
+                    printf("%s: invalid mode: %d\n", __func__, machine_mode);
63
+                    machine_mode = 0;
64
+                    ui_redraw();
65
+                    return;
66
+                }
67
+            }
39
             break;
68
             break;
40
         }
69
         }
41
 
70
 
42
         case UI_LENGTH: {
71
         case UI_LENGTH: {
43
-            // TODO
72
+            snprintf(mode, sizeof(mode) - 1, "Length:");
73
+            snprintf(val, sizeof(val) - 1, "%"PRIu32, sequence_get_beats());
44
             break;
74
             break;
45
         }
75
         }
46
 
76
 
47
         case UI_BANK: {
77
         case UI_BANK: {
48
-            // TODO
78
+            snprintf(mode, sizeof(mode) - 1, "Bank:");
79
+            snprintf(val, sizeof(val) - 1, "%"PRIu32, sequence_get_bank());
49
             break;
80
             break;
50
         }
81
         }
51
 
82
 
53
             printf("%s: invalid mode: %d\n", __func__, ui_mode);
84
             printf("%s: invalid mode: %d\n", __func__, ui_mode);
54
             ui_mode = 0;
85
             ui_mode = 0;
55
             ui_redraw();
86
             ui_redraw();
56
-            break;
87
+            return;
57
         }
88
         }
58
     }
89
     }
90
+
91
+    snprintf(bat, sizeof(bat) - 1, "Bat: %.2fV", bat_get());
92
+    lcd_draw(mode, val, bat);
59
 }
93
 }
60
 
94
 
61
 static void ui_buttons_loopstation(enum buttons btn, bool val) {
95
 static void ui_buttons_loopstation(enum buttons btn, bool val) {
103
 static void ui_buttons(enum buttons btn, bool val) {
137
 static void ui_buttons(enum buttons btn, bool val) {
104
     switch (btn) {
138
     switch (btn) {
105
         case BTN_CLICK: {
139
         case BTN_CLICK: {
106
-            ui_mode = (ui_mode + 1) % UI_NUM_MODES;
107
-            ui_redraw();
140
+            if (val) {
141
+                ui_mode = (ui_mode + 1) % UI_NUM_MODES;
142
+                ui_redraw();
143
+            }
108
             break;
144
             break;
109
         }
145
         }
110
 
146
 
139
 
175
 
140
     switch (ui_mode) {
176
     switch (ui_mode) {
141
         case UI_BPM: {
177
         case UI_BPM: {
142
-            // TODO
178
+            sequence_set_bpm(sequence_get_bpm() + val);
143
             break;
179
             break;
144
         }
180
         }
145
 
181
 
146
         case UI_MODE: {
182
         case UI_MODE: {
147
-            // TODO
183
+            machine_mode = (machine_mode + val) % MACHINE_NUM_MODES;
148
             break;
184
             break;
149
         }
185
         }
150
 
186
 
151
         case UI_LENGTH: {
187
         case UI_LENGTH: {
152
-            // TODO
188
+            sequence_set_beats(sequence_get_beats() + val);
153
             break;
189
             break;
154
         }
190
         }
155
 
191
 
156
         case UI_BANK: {
192
         case UI_BANK: {
157
-            // TODO
193
+            sequence_set_bank(sequence_get_bank() + val);
158
             break;
194
             break;
159
         }
195
         }
160
 
196
 
162
             printf("%s: invalid mode: %d\n", __func__, ui_mode);
198
             printf("%s: invalid mode: %d\n", __func__, ui_mode);
163
             ui_mode = 0;
199
             ui_mode = 0;
164
             ui_encoder(val);
200
             ui_encoder(val);
165
-            break;
201
+            return;
166
         }
202
         }
167
     }
203
     }
204
+
205
+    ui_redraw();
168
 }
206
 }
169
 
207
 
170
 void ui_init(void) {
208
 void ui_init(void) {
171
     buttons_callback(ui_buttons);
209
     buttons_callback(ui_buttons);
172
     ui_redraw();
210
     ui_redraw();
173
 }
211
 }
212
+
213
+void ui_run(void) {
214
+    uint32_t now = to_ms_since_boot(get_absolute_time());
215
+    if (now >= (last_redraw + REDRAW_MS)) {
216
+        ui_redraw();
217
+        last_redraw = now;
218
+    }
219
+}

Loading…
Cancel
Save