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,6 +30,7 @@ pico_sdk_init()
30 30
 add_executable(drumkit)
31 31
 
32 32
 target_sources(drumkit PUBLIC
33
+    src/adc.c
33 34
     src/buttons.c
34 35
     src/encoder.c
35 36
     src/lcd.c

+ 1
- 1
README.md View File

@@ -53,7 +53,7 @@ It uses the [Pi Pico SDK](https://github.com/raspberrypi/pico-sdk), licensed as
53 53
 
54 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 58
     This program is free software: you can redistribute it and/or modify
59 59
     it under the terms of the GNU General Public License as published by

+ 25
- 0
include/adc.h View File

@@ -0,0 +1,25 @@
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,4 +35,3 @@ void buttons_callback(void (*fp)(enum buttons, bool));
35 35
 void buttons_run(void);
36 36
 
37 37
 #endif // __BUTTONS_H__
38
-

+ 0
- 1
include/encoder.h View File

@@ -26,4 +26,3 @@ int32_t encoder_pos(void);
26 26
 void encoder_run(void);
27 27
 
28 28
 #endif // __ENCODER_H__
29
-

+ 1
- 0
include/lcd.h View File

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

+ 12
- 0
include/sequence.h View File

@@ -36,11 +36,23 @@ enum channels {
36 36
 
37 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 42
 void sequence_init(void);
43
+
40 44
 void sequence_set_bpm(uint32_t new_bpm);
45
+uint32_t sequence_get_bpm(void);
46
+
41 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 53
 void sequence_handle_button_loopstation(enum buttons btn, bool rec);
43 54
 void sequence_handle_button_drummachine(enum buttons btn);
55
+
44 56
 void sequence_run(void);
45 57
 
46 58
 #endif // __SEQUENCE_H__

+ 1
- 0
include/ui.h View File

@@ -39,5 +39,6 @@ enum machine_modes {
39 39
 
40 40
 void ui_init(void);
41 41
 void ui_encoder(int32_t val);
42
+void ui_run(void);
42 43
 
43 44
 #endif // __UI_H__

+ 47
- 0
src/adc.c View File

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

+ 10
- 0
src/lcd.c View File

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

+ 26
- 1
src/sequence.c View File

@@ -23,13 +23,13 @@
23 23
 #include "pulse.h"
24 24
 #include "sequence.h"
25 25
 
26
-#define MAX_BEATS 32
27 26
 static const uint32_t channel_times[NUM_CHANNELS] = CH_GPIO_TIMINGS;
28 27
 
29 28
 static uint32_t ms_per_beat = 500;
30 29
 static uint32_t beats = 16;
31 30
 static uint32_t last_t = 0;
32 31
 static uint32_t last_i = 0;
32
+static uint32_t bank = 0;
33 33
 
34 34
 static enum channels sequence[MAX_BEATS] = {0};
35 35
 
@@ -46,8 +46,30 @@ void sequence_set_bpm(uint32_t new_bpm) {
46 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 53
 void sequence_set_beats(uint32_t new_beats) {
50 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 75
 static void sequence_set(uint32_t beat, enum channels ch, bool value) {
@@ -123,18 +145,21 @@ void sequence_handle_button_drummachine(enum buttons btn) {
123 145
 
124 146
     switch (btn) {
125 147
         case BTN_A: {
148
+            // TODO kick is wrong here
126 149
             bool val = !sequence_get(beat, CH_KICK);
127 150
             sequence_set(beat, CH_KICK, val);
128 151
             break;
129 152
         }
130 153
 
131 154
         case BTN_B: {
155
+            // TODO snare is wrong here
132 156
             bool val = !sequence_get(beat, CH_SNARE);
133 157
             sequence_set(beat, CH_SNARE, val);
134 158
             break;
135 159
         }
136 160
 
137 161
         case BTN_C: {
162
+            // TODO hihat is wrong here
138 163
             bool val = !sequence_get(beat, CH_HIHAT);
139 164
             sequence_set(beat, CH_HIHAT, val);
140 165
             break;

+ 58
- 12
src/ui.c View File

@@ -17,35 +17,66 @@
17 17
  */
18 18
 
19 19
 #include <stdio.h>
20
+#include <inttypes.h>
20 21
 #include "pico/stdlib.h"
21 22
 
23
+#include "adc.h"
22 24
 #include "buttons.h"
25
+#include "lcd.h"
23 26
 #include "sequence.h"
24 27
 #include "ui.h"
25 28
 
29
+#define REDRAW_MS 2000
30
+
26 31
 static bool rec_held_down = false;
27 32
 static enum ui_modes ui_mode = 0;
28 33
 static enum machine_modes machine_mode = 0;
34
+static uint32_t last_redraw = 0;
29 35
 
30 36
 static void ui_redraw(void) {
37
+    char mode[64] = {0};
38
+    char val[64] = {0};
39
+    char bat[64] = {0};
40
+
31 41
     switch (ui_mode) {
32 42
         case UI_BPM: {
33
-            // TODO
43
+            snprintf(mode, sizeof(mode) - 1, "BPM:");
44
+            snprintf(val, sizeof(val) - 1, "%"PRIu32, sequence_get_bpm());
34 45
             break;
35 46
         }
36 47
 
37 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 68
             break;
40 69
         }
41 70
 
42 71
         case UI_LENGTH: {
43
-            // TODO
72
+            snprintf(mode, sizeof(mode) - 1, "Length:");
73
+            snprintf(val, sizeof(val) - 1, "%"PRIu32, sequence_get_beats());
44 74
             break;
45 75
         }
46 76
 
47 77
         case UI_BANK: {
48
-            // TODO
78
+            snprintf(mode, sizeof(mode) - 1, "Bank:");
79
+            snprintf(val, sizeof(val) - 1, "%"PRIu32, sequence_get_bank());
49 80
             break;
50 81
         }
51 82
 
@@ -53,9 +84,12 @@ static void ui_redraw(void) {
53 84
             printf("%s: invalid mode: %d\n", __func__, ui_mode);
54 85
             ui_mode = 0;
55 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 95
 static void ui_buttons_loopstation(enum buttons btn, bool val) {
@@ -103,8 +137,10 @@ static void ui_buttons_drummachine(enum buttons btn, bool val) {
103 137
 static void ui_buttons(enum buttons btn, bool val) {
104 138
     switch (btn) {
105 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 144
             break;
109 145
         }
110 146
 
@@ -139,22 +175,22 @@ void ui_encoder(int32_t val) {
139 175
 
140 176
     switch (ui_mode) {
141 177
         case UI_BPM: {
142
-            // TODO
178
+            sequence_set_bpm(sequence_get_bpm() + val);
143 179
             break;
144 180
         }
145 181
 
146 182
         case UI_MODE: {
147
-            // TODO
183
+            machine_mode = (machine_mode + val) % MACHINE_NUM_MODES;
148 184
             break;
149 185
         }
150 186
 
151 187
         case UI_LENGTH: {
152
-            // TODO
188
+            sequence_set_beats(sequence_get_beats() + val);
153 189
             break;
154 190
         }
155 191
 
156 192
         case UI_BANK: {
157
-            // TODO
193
+            sequence_set_bank(sequence_get_bank() + val);
158 194
             break;
159 195
         }
160 196
 
@@ -162,12 +198,22 @@ void ui_encoder(int32_t val) {
162 198
             printf("%s: invalid mode: %d\n", __func__, ui_mode);
163 199
             ui_mode = 0;
164 200
             ui_encoder(val);
165
-            break;
201
+            return;
166 202
         }
167 203
     }
204
+
205
+    ui_redraw();
168 206
 }
169 207
 
170 208
 void ui_init(void) {
171 209
     buttons_callback(ui_buttons);
172 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