diff options
Diffstat (limited to 'platforms')
40 files changed, 3047 insertions, 93 deletions
diff --git a/platforms/arm_atsam/flash.mk b/platforms/arm_atsam/flash.mk index f31d4b4d9..8152610ce 100644 --- a/platforms/arm_atsam/flash.mk +++ b/platforms/arm_atsam/flash.mk | |||
@@ -3,9 +3,20 @@ | |||
3 | # Architecture or project specific options | 3 | # Architecture or project specific options |
4 | # | 4 | # |
5 | 5 | ||
6 | MDLOADER_CLI ?= mdloader | ||
7 | |||
8 | define EXEC_MDLOADER | ||
9 | $(MDLOADER_CLI) --first --download $(BUILD_DIR)/$(TARGET).bin --restart | ||
10 | endef | ||
11 | |||
12 | mdloader: bin | ||
13 | $(call EXEC_MDLOADER) | ||
14 | |||
6 | flash: bin | 15 | flash: bin |
7 | ifneq ($(strip $(PROGRAM_CMD)),) | 16 | ifneq ($(strip $(PROGRAM_CMD)),) |
8 | $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD) | 17 | $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD) |
18 | else ifeq ($(strip $(ARM_ATSAM)),SAMD51J18A) | ||
19 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_MDLOADER) | ||
9 | else | 20 | else |
10 | $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_ARCH)" | 21 | $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_ARCH)" |
11 | endif | 22 | endif |
diff --git a/platforms/avr/drivers/analog.c b/platforms/avr/drivers/analog.c index 8d299ffdb..628835cce 100644 --- a/platforms/avr/drivers/analog.c +++ b/platforms/avr/drivers/analog.c | |||
@@ -23,29 +23,6 @@ static uint8_t aref = ADC_REF_POWER; | |||
23 | 23 | ||
24 | void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); } | 24 | void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); } |
25 | 25 | ||
26 | // Arduino compatible pin input | ||
27 | int16_t analogRead(uint8_t pin) { | ||
28 | #if defined(__AVR_ATmega32U4__) | ||
29 | // clang-format off | ||
30 | static const uint8_t PROGMEM pin_to_mux[] = { | ||
31 | //A0 A1 A2 A3 A4 A5 | ||
32 | //F7 F6 F5 F4 F1 F0 | ||
33 | 0x07, 0x06, 0x05, 0x04, 0x01, 0x00, | ||
34 | //A6 A7 A8 A9 A10 A11 | ||
35 | //D4 D7 B4 B5 B6 D6 | ||
36 | 0x20, 0x22, 0x23, 0x24, 0x25, 0x21 | ||
37 | }; | ||
38 | // clang-format on | ||
39 | if (pin >= 12) return 0; | ||
40 | return adc_read(pgm_read_byte(pin_to_mux + pin)); | ||
41 | #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) | ||
42 | if (pin >= 8) return 0; | ||
43 | return adc_read(pin); | ||
44 | #else | ||
45 | return 0; | ||
46 | #endif | ||
47 | } | ||
48 | |||
49 | int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); } | 26 | int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); } |
50 | 27 | ||
51 | uint8_t pinToMux(pin_t pin) { | 28 | uint8_t pinToMux(pin_t pin) { |
diff --git a/platforms/avr/drivers/analog.h b/platforms/avr/drivers/analog.h index 058882450..b3c05e197 100644 --- a/platforms/avr/drivers/analog.h +++ b/platforms/avr/drivers/analog.h | |||
@@ -23,7 +23,6 @@ | |||
23 | extern "C" { | 23 | extern "C" { |
24 | #endif | 24 | #endif |
25 | void analogReference(uint8_t mode); | 25 | void analogReference(uint8_t mode); |
26 | int16_t analogRead(uint8_t pin); | ||
27 | 26 | ||
28 | int16_t analogReadPin(pin_t pin); | 27 | int16_t analogReadPin(pin_t pin); |
29 | uint8_t pinToMux(pin_t pin); | 28 | uint8_t pinToMux(pin_t pin); |
diff --git a/platforms/avr/drivers/audio_pwm.h b/platforms/avr/drivers/audio_pwm.h new file mode 100644 index 000000000..d6eb3571d --- /dev/null +++ b/platforms/avr/drivers/audio_pwm.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* Copyright 2020 Jack Humbert | ||
2 | * Copyright 2020 JohSchneider | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | #pragma once | ||
diff --git a/platforms/avr/drivers/audio_pwm_hardware.c b/platforms/avr/drivers/audio_pwm_hardware.c new file mode 100644 index 000000000..df03a4558 --- /dev/null +++ b/platforms/avr/drivers/audio_pwm_hardware.c | |||
@@ -0,0 +1,332 @@ | |||
1 | /* Copyright 2016 Jack Humbert | ||
2 | * Copyright 2020 JohSchneider | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #if defined(__AVR__) | ||
19 | # include <avr/pgmspace.h> | ||
20 | # include <avr/interrupt.h> | ||
21 | # include <avr/io.h> | ||
22 | #endif | ||
23 | |||
24 | #include "audio.h" | ||
25 | |||
26 | extern bool playing_note; | ||
27 | extern bool playing_melody; | ||
28 | extern uint8_t note_timbre; | ||
29 | |||
30 | #define CPU_PRESCALER 8 | ||
31 | |||
32 | /* | ||
33 | Audio Driver: PWM | ||
34 | |||
35 | drive up to two speakers through the AVR PWM hardware-peripheral, using timer1 and/or timer3 on Atmega32U4. | ||
36 | |||
37 | the primary channel_1 can be connected to either pin PC4 PC5 or PC6 (the later being used by most AVR based keyboards) with a PMW signal generated by timer3 | ||
38 | and an optional secondary channel_2 on either pin PB5, PB6 or PB7, with a PWM signal from timer1 | ||
39 | |||
40 | alternatively, the PWM pins on PORTB can be used as only/primary speaker | ||
41 | */ | ||
42 | |||
43 | #if defined(AUDIO_PIN) && (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) && (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN != D5) | ||
44 | # error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under the AVR settings for available options." | ||
45 | #endif | ||
46 | |||
47 | #if (AUDIO_PIN == C4) || (AUDIO_PIN == C5) || (AUDIO_PIN == C6) | ||
48 | # define AUDIO1_PIN_SET | ||
49 | # define AUDIO1_TIMSKx TIMSK3 | ||
50 | # define AUDIO1_TCCRxA TCCR3A | ||
51 | # define AUDIO1_TCCRxB TCCR3B | ||
52 | # define AUDIO1_ICRx ICR3 | ||
53 | # define AUDIO1_WGMx0 WGM30 | ||
54 | # define AUDIO1_WGMx1 WGM31 | ||
55 | # define AUDIO1_WGMx2 WGM32 | ||
56 | # define AUDIO1_WGMx3 WGM33 | ||
57 | # define AUDIO1_CSx0 CS30 | ||
58 | # define AUDIO1_CSx1 CS31 | ||
59 | # define AUDIO1_CSx2 CS32 | ||
60 | |||
61 | # if (AUDIO_PIN == C6) | ||
62 | # define AUDIO1_COMxy0 COM3A0 | ||
63 | # define AUDIO1_COMxy1 COM3A1 | ||
64 | # define AUDIO1_OCIExy OCIE3A | ||
65 | # define AUDIO1_OCRxy OCR3A | ||
66 | # define AUDIO1_PIN C6 | ||
67 | # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPA_vect | ||
68 | # elif (AUDIO_PIN == C5) | ||
69 | # define AUDIO1_COMxy0 COM3B0 | ||
70 | # define AUDIO1_COMxy1 COM3B1 | ||
71 | # define AUDIO1_OCIExy OCIE3B | ||
72 | # define AUDIO1_OCRxy OCR3B | ||
73 | # define AUDIO1_PIN C5 | ||
74 | # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPB_vect | ||
75 | # elif (AUDIO_PIN == C4) | ||
76 | # define AUDIO1_COMxy0 COM3C0 | ||
77 | # define AUDIO1_COMxy1 COM3C1 | ||
78 | # define AUDIO1_OCIExy OCIE3C | ||
79 | # define AUDIO1_OCRxy OCR3C | ||
80 | # define AUDIO1_PIN C4 | ||
81 | # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPC_vect | ||
82 | # endif | ||
83 | #endif | ||
84 | |||
85 | #if defined(AUDIO_PIN) && defined(AUDIO_PIN_ALT) && (AUDIO_PIN == AUDIO_PIN_ALT) | ||
86 | # error "Audio feature: AUDIO_PIN and AUDIO_PIN_ALT on the same pin makes no sense." | ||
87 | #endif | ||
88 | |||
89 | #if ((AUDIO_PIN == B5) && ((AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B6) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B7) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6))) | ||
90 | # error "Audio feature: PORTB as AUDIO_PIN and AUDIO_PIN_ALT at the same time is not supported." | ||
91 | #endif | ||
92 | |||
93 | #if defined(AUDIO_PIN_ALT) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7) | ||
94 | # error "Audio feature: the pin selected as AUDIO_PIN_ALT is not supported." | ||
95 | #endif | ||
96 | |||
97 | #if (AUDIO_PIN == B5) || (AUDIO_PIN == B6) || (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7) || (AUDIO_PIN == D5) | ||
98 | # define AUDIO2_PIN_SET | ||
99 | # define AUDIO2_TIMSKx TIMSK1 | ||
100 | # define AUDIO2_TCCRxA TCCR1A | ||
101 | # define AUDIO2_TCCRxB TCCR1B | ||
102 | # define AUDIO2_ICRx ICR1 | ||
103 | # define AUDIO2_WGMx0 WGM10 | ||
104 | # define AUDIO2_WGMx1 WGM11 | ||
105 | # define AUDIO2_WGMx2 WGM12 | ||
106 | # define AUDIO2_WGMx3 WGM13 | ||
107 | # define AUDIO2_CSx0 CS10 | ||
108 | # define AUDIO2_CSx1 CS11 | ||
109 | # define AUDIO2_CSx2 CS12 | ||
110 | |||
111 | # if (AUDIO_PIN == B5) || (AUDIO_PIN_ALT == B5) | ||
112 | # define AUDIO2_COMxy0 COM1A0 | ||
113 | # define AUDIO2_COMxy1 COM1A1 | ||
114 | # define AUDIO2_OCIExy OCIE1A | ||
115 | # define AUDIO2_OCRxy OCR1A | ||
116 | # define AUDIO2_PIN B5 | ||
117 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect | ||
118 | # elif (AUDIO_PIN == B6) || (AUDIO_PIN_ALT == B6) | ||
119 | # define AUDIO2_COMxy0 COM1B0 | ||
120 | # define AUDIO2_COMxy1 COM1B1 | ||
121 | # define AUDIO2_OCIExy OCIE1B | ||
122 | # define AUDIO2_OCRxy OCR1B | ||
123 | # define AUDIO2_PIN B6 | ||
124 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPB_vect | ||
125 | # elif (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B7) | ||
126 | # define AUDIO2_COMxy0 COM1C0 | ||
127 | # define AUDIO2_COMxy1 COM1C1 | ||
128 | # define AUDIO2_OCIExy OCIE1C | ||
129 | # define AUDIO2_OCRxy OCR1C | ||
130 | # define AUDIO2_PIN B7 | ||
131 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPC_vect | ||
132 | # elif (AUDIO_PIN == D5) && defined(__AVR_ATmega32A__) | ||
133 | # pragma message "Audio support for ATmega32A is experimental and can cause crashes." | ||
134 | # undef AUDIO2_TIMSKx | ||
135 | # define AUDIO2_TIMSKx TIMSK | ||
136 | # define AUDIO2_COMxy0 COM1A0 | ||
137 | # define AUDIO2_COMxy1 COM1A1 | ||
138 | # define AUDIO2_OCIExy OCIE1A | ||
139 | # define AUDIO2_OCRxy OCR1A | ||
140 | # define AUDIO2_PIN D5 | ||
141 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect | ||
142 | # endif | ||
143 | #endif | ||
144 | |||
145 | // C6 seems to be the assumed default by many existing keyboard - but sill warn the user | ||
146 | #if !defined(AUDIO1_PIN_SET) && !defined(AUDIO2_PIN_SET) | ||
147 | # pragma message "Audio feature enabled, but no suitable pin selected - see docs/feature_audio under the AVR settings for available options. Don't expect to hear anything... :-)" | ||
148 | // TODO: make this an error - go through the breaking-change-process and change all keyboards to the new define | ||
149 | #endif | ||
150 | // ----------------------------------------------------------------------------- | ||
151 | |||
152 | #ifdef AUDIO1_PIN_SET | ||
153 | static float channel_1_frequency = 0.0f; | ||
154 | void channel_1_set_frequency(float freq) { | ||
155 | if (freq == 0.0f) // a pause/rest is a valid "note" with freq=0 | ||
156 | { | ||
157 | // disable the output, but keep the pwm-ISR going (with the previous | ||
158 | // frequency) so the audio-state keeps getting updated | ||
159 | // Note: setting the duty-cycle 0 is not possible on non-inverting PWM mode - see the AVR data-sheet | ||
160 | AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0)); | ||
161 | return; | ||
162 | } else { | ||
163 | AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); // enable output, PWM mode | ||
164 | } | ||
165 | |||
166 | channel_1_frequency = freq; | ||
167 | |||
168 | // set pwm period | ||
169 | AUDIO1_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
170 | // and duty cycle | ||
171 | AUDIO1_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100); | ||
172 | } | ||
173 | |||
174 | void channel_1_start(void) { | ||
175 | // enable timer-counter ISR | ||
176 | AUDIO1_TIMSKx |= _BV(AUDIO1_OCIExy); | ||
177 | // enable timer-counter output | ||
178 | AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); | ||
179 | } | ||
180 | |||
181 | void channel_1_stop(void) { | ||
182 | // disable timer-counter ISR | ||
183 | AUDIO1_TIMSKx &= ~_BV(AUDIO1_OCIExy); | ||
184 | // disable timer-counter output | ||
185 | AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0)); | ||
186 | } | ||
187 | #endif | ||
188 | |||
189 | #ifdef AUDIO2_PIN_SET | ||
190 | static float channel_2_frequency = 0.0f; | ||
191 | void channel_2_set_frequency(float freq) { | ||
192 | if (freq == 0.0f) { | ||
193 | AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0)); | ||
194 | return; | ||
195 | } else { | ||
196 | AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1); | ||
197 | } | ||
198 | |||
199 | channel_2_frequency = freq; | ||
200 | |||
201 | AUDIO2_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
202 | AUDIO2_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100); | ||
203 | } | ||
204 | |||
205 | float channel_2_get_frequency(void) { return channel_2_frequency; } | ||
206 | |||
207 | void channel_2_start(void) { | ||
208 | AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy); | ||
209 | AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1); | ||
210 | } | ||
211 | |||
212 | void channel_2_stop(void) { | ||
213 | AUDIO2_TIMSKx &= ~_BV(AUDIO2_OCIExy); | ||
214 | AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0)); | ||
215 | } | ||
216 | #endif | ||
217 | |||
218 | void audio_driver_initialize() { | ||
219 | #ifdef AUDIO1_PIN_SET | ||
220 | channel_1_stop(); | ||
221 | setPinOutput(AUDIO1_PIN); | ||
222 | #endif | ||
223 | |||
224 | #ifdef AUDIO2_PIN_SET | ||
225 | channel_2_stop(); | ||
226 | setPinOutput(AUDIO2_PIN); | ||
227 | #endif | ||
228 | |||
229 | // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B | ||
230 | // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation | ||
231 | // OC3A -- PC6 | ||
232 | // OC3B -- PC5 | ||
233 | // OC3C -- PC4 | ||
234 | // OC1A -- PB5 | ||
235 | // OC1B -- PB6 | ||
236 | // OC1C -- PB7 | ||
237 | |||
238 | // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A) | ||
239 | // OCR3A - PC6 | ||
240 | // OCR3B - PC5 | ||
241 | // OCR3C - PC4 | ||
242 | // OCR1A - PB5 | ||
243 | // OCR1B - PB6 | ||
244 | // OCR1C - PB7 | ||
245 | |||
246 | // Clock Select (CS3n) = 0b010 = Clock / 8 | ||
247 | #ifdef AUDIO1_PIN_SET | ||
248 | // initialize timer-counter | ||
249 | AUDIO1_TCCRxA = (0 << AUDIO1_COMxy1) | (0 << AUDIO1_COMxy0) | (1 << AUDIO1_WGMx1) | (0 << AUDIO1_WGMx0); | ||
250 | AUDIO1_TCCRxB = (1 << AUDIO1_WGMx3) | (1 << AUDIO1_WGMx2) | (0 << AUDIO1_CSx2) | (1 << AUDIO1_CSx1) | (0 << AUDIO1_CSx0); | ||
251 | #endif | ||
252 | |||
253 | #ifdef AUDIO2_PIN_SET | ||
254 | AUDIO2_TCCRxA = (0 << AUDIO2_COMxy1) | (0 << AUDIO2_COMxy0) | (1 << AUDIO2_WGMx1) | (0 << AUDIO2_WGMx0); | ||
255 | AUDIO2_TCCRxB = (1 << AUDIO2_WGMx3) | (1 << AUDIO2_WGMx2) | (0 << AUDIO2_CSx2) | (1 << AUDIO2_CSx1) | (0 << AUDIO2_CSx0); | ||
256 | #endif | ||
257 | } | ||
258 | |||
259 | void audio_driver_stop() { | ||
260 | #ifdef AUDIO1_PIN_SET | ||
261 | channel_1_stop(); | ||
262 | #endif | ||
263 | |||
264 | #ifdef AUDIO2_PIN_SET | ||
265 | channel_2_stop(); | ||
266 | #endif | ||
267 | } | ||
268 | |||
269 | void audio_driver_start(void) { | ||
270 | #ifdef AUDIO1_PIN_SET | ||
271 | channel_1_start(); | ||
272 | if (playing_note) { | ||
273 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
274 | } | ||
275 | #endif | ||
276 | |||
277 | #if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET) | ||
278 | channel_2_start(); | ||
279 | if (playing_note) { | ||
280 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
281 | } | ||
282 | #endif | ||
283 | } | ||
284 | |||
285 | static volatile uint32_t isr_counter = 0; | ||
286 | #ifdef AUDIO1_PIN_SET | ||
287 | ISR(AUDIO1_TIMERx_COMPy_vect) { | ||
288 | isr_counter++; | ||
289 | if (isr_counter < channel_1_frequency / (CPU_PRESCALER * 8)) return; | ||
290 | |||
291 | isr_counter = 0; | ||
292 | bool state_changed = audio_update_state(); | ||
293 | |||
294 | if (!playing_note && !playing_melody) { | ||
295 | channel_1_stop(); | ||
296 | # ifdef AUDIO2_PIN_SET | ||
297 | channel_2_stop(); | ||
298 | # endif | ||
299 | return; | ||
300 | } | ||
301 | |||
302 | if (state_changed) { | ||
303 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
304 | # ifdef AUDIO2_PIN_SET | ||
305 | if (audio_get_number_of_active_tones() > 1) { | ||
306 | channel_2_set_frequency(audio_get_processed_frequency(1)); | ||
307 | } else { | ||
308 | channel_2_stop(); | ||
309 | } | ||
310 | # endif | ||
311 | } | ||
312 | } | ||
313 | #endif | ||
314 | |||
315 | #if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET) | ||
316 | ISR(AUDIO2_TIMERx_COMPy_vect) { | ||
317 | isr_counter++; | ||
318 | if (isr_counter < channel_2_frequency / (CPU_PRESCALER * 8)) return; | ||
319 | |||
320 | isr_counter = 0; | ||
321 | bool state_changed = audio_update_state(); | ||
322 | |||
323 | if (!playing_note && !playing_melody) { | ||
324 | channel_2_stop(); | ||
325 | return; | ||
326 | } | ||
327 | |||
328 | if (state_changed) { | ||
329 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
330 | } | ||
331 | } | ||
332 | #endif | ||
diff --git a/platforms/avr/drivers/i2c_master.c b/platforms/avr/drivers/i2c_master.c index 2773e0077..111b55d6b 100644 --- a/platforms/avr/drivers/i2c_master.c +++ b/platforms/avr/drivers/i2c_master.c | |||
@@ -202,6 +202,25 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, | |||
202 | return status; | 202 | return status; |
203 | } | 203 | } |
204 | 204 | ||
205 | i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { | ||
206 | i2c_status_t status = i2c_start(devaddr | 0x00, timeout); | ||
207 | if (status >= 0) { | ||
208 | status = i2c_write(regaddr >> 8, timeout); | ||
209 | |||
210 | if (status >= 0) { | ||
211 | status = i2c_write(regaddr & 0xFF, timeout); | ||
212 | |||
213 | for (uint16_t i = 0; i < length && status >= 0; i++) { | ||
214 | status = i2c_write(data[i], timeout); | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | |||
219 | i2c_stop(); | ||
220 | |||
221 | return status; | ||
222 | } | ||
223 | |||
205 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { | 224 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { |
206 | i2c_status_t status = i2c_start(devaddr, timeout); | 225 | i2c_status_t status = i2c_start(devaddr, timeout); |
207 | if (status < 0) { | 226 | if (status < 0) { |
@@ -235,6 +254,43 @@ error: | |||
235 | return (status < 0) ? status : I2C_STATUS_SUCCESS; | 254 | return (status < 0) ? status : I2C_STATUS_SUCCESS; |
236 | } | 255 | } |
237 | 256 | ||
257 | i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { | ||
258 | i2c_status_t status = i2c_start(devaddr, timeout); | ||
259 | if (status < 0) { | ||
260 | goto error; | ||
261 | } | ||
262 | |||
263 | status = i2c_write(regaddr >> 8, timeout); | ||
264 | if (status < 0) { | ||
265 | goto error; | ||
266 | } | ||
267 | status = i2c_write(regaddr & 0xFF, timeout); | ||
268 | if (status < 0) { | ||
269 | goto error; | ||
270 | } | ||
271 | |||
272 | status = i2c_start(devaddr | 0x01, timeout); | ||
273 | |||
274 | for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) { | ||
275 | status = i2c_read_ack(timeout); | ||
276 | if (status >= 0) { | ||
277 | data[i] = status; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | if (status >= 0) { | ||
282 | status = i2c_read_nack(timeout); | ||
283 | if (status >= 0) { | ||
284 | data[(length - 1)] = status; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | error: | ||
289 | i2c_stop(); | ||
290 | |||
291 | return (status < 0) ? status : I2C_STATUS_SUCCESS; | ||
292 | } | ||
293 | |||
238 | void i2c_stop(void) { | 294 | void i2c_stop(void) { |
239 | // transmit STOP condition | 295 | // transmit STOP condition |
240 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); | 296 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); |
diff --git a/platforms/avr/drivers/i2c_master.h b/platforms/avr/drivers/i2c_master.h index e5af73364..2d95846db 100644 --- a/platforms/avr/drivers/i2c_master.h +++ b/platforms/avr/drivers/i2c_master.h | |||
@@ -39,5 +39,7 @@ int16_t i2c_read_nack(uint16_t timeout); | |||
39 | i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); | 39 | i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); |
40 | i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); | 40 | i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); |
41 | i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); | 41 | i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); |
42 | i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); | ||
42 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); | 43 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); |
44 | i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); | ||
43 | void i2c_stop(void); | 45 | void i2c_stop(void); |
diff --git a/platforms/avr/drivers/ps2/ps2_io.c b/platforms/avr/drivers/ps2/ps2_io.c new file mode 100644 index 000000000..7c826fbf1 --- /dev/null +++ b/platforms/avr/drivers/ps2/ps2_io.c | |||
@@ -0,0 +1,51 @@ | |||
1 | #include <stdbool.h> | ||
2 | #include "ps2_io.h" | ||
3 | #include "gpio.h" | ||
4 | #include "wait.h" | ||
5 | |||
6 | /* Check port settings for clock and data line */ | ||
7 | #if !(defined(PS2_CLOCK_PIN)) | ||
8 | # error "PS/2 clock setting is required in config.h" | ||
9 | #endif | ||
10 | |||
11 | #if !(defined(PS2_DATA_PIN)) | ||
12 | # error "PS/2 data setting is required in config.h" | ||
13 | #endif | ||
14 | |||
15 | /* | ||
16 | * Clock | ||
17 | */ | ||
18 | void clock_init(void) {} | ||
19 | |||
20 | void clock_lo(void) { | ||
21 | // Transition from input with pull-up to output low via Hi-Z instead of output high | ||
22 | writePinLow(PS2_CLOCK_PIN); | ||
23 | setPinOutput(PS2_CLOCK_PIN); | ||
24 | } | ||
25 | |||
26 | void clock_hi(void) { setPinInputHigh(PS2_CLOCK_PIN); } | ||
27 | |||
28 | bool clock_in(void) { | ||
29 | setPinInputHigh(PS2_CLOCK_PIN); | ||
30 | wait_us(1); | ||
31 | return readPin(PS2_CLOCK_PIN); | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * Data | ||
36 | */ | ||
37 | void data_init(void) {} | ||
38 | |||
39 | void data_lo(void) { | ||
40 | // Transition from input with pull-up to output low via Hi-Z instead of output high | ||
41 | writePinLow(PS2_DATA_PIN); | ||
42 | setPinOutput(PS2_DATA_PIN); | ||
43 | } | ||
44 | |||
45 | void data_hi(void) { setPinInputHigh(PS2_DATA_PIN); } | ||
46 | |||
47 | bool data_in(void) { | ||
48 | setPinInputHigh(PS2_DATA_PIN); | ||
49 | wait_us(1); | ||
50 | return readPin(PS2_DATA_PIN); | ||
51 | } | ||
diff --git a/platforms/avr/drivers/ps2/ps2_usart.c b/platforms/avr/drivers/ps2/ps2_usart.c new file mode 100644 index 000000000..151cfcd68 --- /dev/null +++ b/platforms/avr/drivers/ps2/ps2_usart.c | |||
@@ -0,0 +1,227 @@ | |||
1 | /* | ||
2 | Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com> | ||
3 | |||
4 | This software is licensed with a Modified BSD License. | ||
5 | All of this is supposed to be Free Software, Open Source, DFSG-free, | ||
6 | GPL-compatible, and OK to use in both free and proprietary applications. | ||
7 | Additions and corrections to this file are welcome. | ||
8 | |||
9 | |||
10 | Redistribution and use in source and binary forms, with or without | ||
11 | modification, are permitted provided that the following conditions are met: | ||
12 | |||
13 | * Redistributions of source code must retain the above copyright | ||
14 | notice, this list of conditions and the following disclaimer. | ||
15 | |||
16 | * Redistributions in binary form must reproduce the above copyright | ||
17 | notice, this list of conditions and the following disclaimer in | ||
18 | the documentation and/or other materials provided with the | ||
19 | distribution. | ||
20 | |||
21 | * Neither the name of the copyright holders nor the names of | ||
22 | contributors may be used to endorse or promote products derived | ||
23 | from this software without specific prior written permission. | ||
24 | |||
25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
28 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
29 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
30 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
31 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
32 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
33 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
34 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
35 | POSSIBILITY OF SUCH DAMAGE. | ||
36 | */ | ||
37 | |||
38 | /* | ||
39 | * PS/2 protocol USART version | ||
40 | */ | ||
41 | |||
42 | #include <stdbool.h> | ||
43 | #include <avr/interrupt.h> | ||
44 | #include <util/delay.h> | ||
45 | #include "gpio.h" | ||
46 | #include "ps2.h" | ||
47 | #include "ps2_io.h" | ||
48 | #include "print.h" | ||
49 | |||
50 | #ifndef PS2_CLOCK_DDR | ||
51 | # define PS2_CLOCK_DDR PORTx_ADDRESS(PS2_CLOCK_PIN) | ||
52 | #endif | ||
53 | #ifndef PS2_CLOCK_BIT | ||
54 | # define PS2_CLOCK_BIT (PS2_CLOCK_PIN & 0xF) | ||
55 | #endif | ||
56 | #ifndef PS2_DATA_DDR | ||
57 | # define PS2_DATA_DDR PORTx_ADDRESS(PS2_DATA_PIN) | ||
58 | #endif | ||
59 | #ifndef PS2_DATA_BIT | ||
60 | # define PS2_DATA_BIT (PS2_DATA_PIN & 0xF) | ||
61 | #endif | ||
62 | |||
63 | #define WAIT(stat, us, err) \ | ||
64 | do { \ | ||
65 | if (!wait_##stat(us)) { \ | ||
66 | ps2_error = err; \ | ||
67 | goto ERROR; \ | ||
68 | } \ | ||
69 | } while (0) | ||
70 | |||
71 | uint8_t ps2_error = PS2_ERR_NONE; | ||
72 | |||
73 | static inline uint8_t pbuf_dequeue(void); | ||
74 | static inline void pbuf_enqueue(uint8_t data); | ||
75 | static inline bool pbuf_has_data(void); | ||
76 | static inline void pbuf_clear(void); | ||
77 | |||
78 | void ps2_host_init(void) { | ||
79 | idle(); // without this many USART errors occur when cable is disconnected | ||
80 | PS2_USART_INIT(); | ||
81 | PS2_USART_RX_INT_ON(); | ||
82 | // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) | ||
83 | //_delay_ms(2500); | ||
84 | } | ||
85 | |||
86 | uint8_t ps2_host_send(uint8_t data) { | ||
87 | bool parity = true; | ||
88 | ps2_error = PS2_ERR_NONE; | ||
89 | |||
90 | PS2_USART_OFF(); | ||
91 | |||
92 | /* terminate a transmission if we have */ | ||
93 | inhibit(); | ||
94 | _delay_us(100); // [4]p.13 | ||
95 | |||
96 | /* 'Request to Send' and Start bit */ | ||
97 | data_lo(); | ||
98 | clock_hi(); | ||
99 | WAIT(clock_lo, 10000, 10); // 10ms [5]p.50 | ||
100 | |||
101 | /* Data bit[2-9] */ | ||
102 | for (uint8_t i = 0; i < 8; i++) { | ||
103 | _delay_us(15); | ||
104 | if (data & (1 << i)) { | ||
105 | parity = !parity; | ||
106 | data_hi(); | ||
107 | } else { | ||
108 | data_lo(); | ||
109 | } | ||
110 | WAIT(clock_hi, 50, 2); | ||
111 | WAIT(clock_lo, 50, 3); | ||
112 | } | ||
113 | |||
114 | /* Parity bit */ | ||
115 | _delay_us(15); | ||
116 | if (parity) { | ||
117 | data_hi(); | ||
118 | } else { | ||
119 | data_lo(); | ||
120 | } | ||
121 | WAIT(clock_hi, 50, 4); | ||
122 | WAIT(clock_lo, 50, 5); | ||
123 | |||
124 | /* Stop bit */ | ||
125 | _delay_us(15); | ||
126 | data_hi(); | ||
127 | |||
128 | /* Ack */ | ||
129 | WAIT(data_lo, 50, 6); | ||
130 | WAIT(clock_lo, 50, 7); | ||
131 | |||
132 | /* wait for idle state */ | ||
133 | WAIT(clock_hi, 50, 8); | ||
134 | WAIT(data_hi, 50, 9); | ||
135 | |||
136 | idle(); | ||
137 | PS2_USART_INIT(); | ||
138 | PS2_USART_RX_INT_ON(); | ||
139 | return ps2_host_recv_response(); | ||
140 | ERROR: | ||
141 | idle(); | ||
142 | PS2_USART_INIT(); | ||
143 | PS2_USART_RX_INT_ON(); | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | uint8_t ps2_host_recv_response(void) { | ||
148 | // Command may take 25ms/20ms at most([5]p.46, [3]p.21) | ||
149 | uint8_t retry = 25; | ||
150 | while (retry-- && !pbuf_has_data()) { | ||
151 | _delay_ms(1); | ||
152 | } | ||
153 | return pbuf_dequeue(); | ||
154 | } | ||
155 | |||
156 | uint8_t ps2_host_recv(void) { | ||
157 | if (pbuf_has_data()) { | ||
158 | ps2_error = PS2_ERR_NONE; | ||
159 | return pbuf_dequeue(); | ||
160 | } else { | ||
161 | ps2_error = PS2_ERR_NODATA; | ||
162 | return 0; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | ISR(PS2_USART_RX_VECT) { | ||
167 | // TODO: request RESEND when error occurs? | ||
168 | uint8_t error = PS2_USART_ERROR; // USART error should be read before data | ||
169 | uint8_t data = PS2_USART_RX_DATA; | ||
170 | if (!error) { | ||
171 | pbuf_enqueue(data); | ||
172 | } else { | ||
173 | xprintf("PS2 USART error: %02X data: %02X\n", error, data); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | /* send LED state to keyboard */ | ||
178 | void ps2_host_set_led(uint8_t led) { | ||
179 | ps2_host_send(0xED); | ||
180 | ps2_host_send(led); | ||
181 | } | ||
182 | |||
183 | /*-------------------------------------------------------------------- | ||
184 | * Ring buffer to store scan codes from keyboard | ||
185 | *------------------------------------------------------------------*/ | ||
186 | #define PBUF_SIZE 32 | ||
187 | static uint8_t pbuf[PBUF_SIZE]; | ||
188 | static uint8_t pbuf_head = 0; | ||
189 | static uint8_t pbuf_tail = 0; | ||
190 | static inline void pbuf_enqueue(uint8_t data) { | ||
191 | uint8_t sreg = SREG; | ||
192 | cli(); | ||
193 | uint8_t next = (pbuf_head + 1) % PBUF_SIZE; | ||
194 | if (next != pbuf_tail) { | ||
195 | pbuf[pbuf_head] = data; | ||
196 | pbuf_head = next; | ||
197 | } else { | ||
198 | print("pbuf: full\n"); | ||
199 | } | ||
200 | SREG = sreg; | ||
201 | } | ||
202 | static inline uint8_t pbuf_dequeue(void) { | ||
203 | uint8_t val = 0; | ||
204 | |||
205 | uint8_t sreg = SREG; | ||
206 | cli(); | ||
207 | if (pbuf_head != pbuf_tail) { | ||
208 | val = pbuf[pbuf_tail]; | ||
209 | pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE; | ||
210 | } | ||
211 | SREG = sreg; | ||
212 | |||
213 | return val; | ||
214 | } | ||
215 | static inline bool pbuf_has_data(void) { | ||
216 | uint8_t sreg = SREG; | ||
217 | cli(); | ||
218 | bool has_data = (pbuf_head != pbuf_tail); | ||
219 | SREG = sreg; | ||
220 | return has_data; | ||
221 | } | ||
222 | static inline void pbuf_clear(void) { | ||
223 | uint8_t sreg = SREG; | ||
224 | cli(); | ||
225 | pbuf_head = pbuf_tail = 0; | ||
226 | SREG = sreg; | ||
227 | } | ||
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk b/platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk new file mode 100644 index 000000000..6c837bb8e --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk | |||
@@ -0,0 +1,9 @@ | |||
1 | # List of all the board related files. | ||
2 | BOARDSRC = $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY/board.c | ||
3 | |||
4 | # Required include directories | ||
5 | BOARDINC = $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY | ||
6 | |||
7 | # Shared variables | ||
8 | ALLCSRC += $(BOARDSRC) | ||
9 | ALLINC += $(BOARDINC) \ No newline at end of file | ||
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h new file mode 100644 index 000000000..8cb771bc1 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* Copyright 2020 Nick Brassel (tzarc) | ||
2 | * | ||
3 | * This program is free software: you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation, either version 3 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | #pragma once | ||
17 | |||
18 | #define STM32_HSECLK 12000000 | ||
19 | // The following is required to disable the pull-down on PA9, when PA9 is used for the keyboard matrix: | ||
20 | #define BOARD_OTG_NOVBUSSENS | ||
21 | |||
22 | #include_next "board.h" | ||
23 | |||
24 | #undef STM32_HSE_BYPASS | ||
25 | |||
26 | #undef STM32F407xx | ||
27 | #define STM32F405xG | ||
28 | #define STM32F405xx | ||
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h new file mode 100644 index 000000000..cc52a953e --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* Copyright 2021 Andrei Purdea | ||
2 | * | ||
3 | * This program is free software: you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation, either version 2 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | /* Address for jumping to bootloader on STM32 chips. */ | ||
18 | /* It is chip dependent, the correct number can be looked up by checking against ST's application note AN2606. | ||
19 | */ | ||
20 | #define STM32_BOOTLOADER_ADDRESS 0x1FFF0000 | ||
21 | #ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP | ||
22 | # define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE | ||
23 | #endif | ||
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h new file mode 100644 index 000000000..d2ec632d9 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h | |||
@@ -0,0 +1,355 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef MCUCONF_H | ||
18 | #define MCUCONF_H | ||
19 | |||
20 | /* | ||
21 | * STM32F4xx drivers configuration. | ||
22 | * The following settings override the default settings present in | ||
23 | * the various device driver implementation headers. | ||
24 | * Note that the settings for each driver only have effect if the whole | ||
25 | * driver is enabled in halconf.h. | ||
26 | * | ||
27 | * IRQ priorities: | ||
28 | * 15...0 Lowest...Highest. | ||
29 | * | ||
30 | * DMA priorities: | ||
31 | * 0...3 Lowest...Highest. | ||
32 | */ | ||
33 | |||
34 | #define STM32F4xx_MCUCONF | ||
35 | #define STM32F405_MCUCONF | ||
36 | #define STM32F415_MCUCONF | ||
37 | #define STM32F407_MCUCONF | ||
38 | #define STM32F417_MCUCONF | ||
39 | |||
40 | /* | ||
41 | * HAL driver system settings. | ||
42 | */ | ||
43 | #define STM32_NO_INIT FALSE | ||
44 | #define STM32_PVD_ENABLE FALSE | ||
45 | #define STM32_PLS STM32_PLS_LEV0 | ||
46 | #define STM32_BKPRAM_ENABLE FALSE | ||
47 | #define STM32_HSI_ENABLED TRUE | ||
48 | #define STM32_LSI_ENABLED TRUE | ||
49 | #define STM32_HSE_ENABLED TRUE | ||
50 | #define STM32_LSE_ENABLED FALSE | ||
51 | #define STM32_CLOCK48_REQUIRED TRUE | ||
52 | #define STM32_SW STM32_SW_PLL | ||
53 | #define STM32_PLLSRC STM32_PLLSRC_HSE | ||
54 | #define STM32_PLLM_VALUE 12 | ||
55 | #define STM32_PLLN_VALUE 336 | ||
56 | #define STM32_PLLP_VALUE 2 | ||
57 | #define STM32_PLLQ_VALUE 7 | ||
58 | #define STM32_HPRE STM32_HPRE_DIV1 | ||
59 | #define STM32_PPRE1 STM32_PPRE1_DIV4 | ||
60 | #define STM32_PPRE2 STM32_PPRE2_DIV2 | ||
61 | #define STM32_RTCSEL STM32_RTCSEL_LSI | ||
62 | #define STM32_RTCPRE_VALUE 8 | ||
63 | #define STM32_MCO1SEL STM32_MCO1SEL_HSI | ||
64 | #define STM32_MCO1PRE STM32_MCO1PRE_DIV1 | ||
65 | #define STM32_MCO2SEL STM32_MCO2SEL_SYSCLK | ||
66 | #define STM32_MCO2PRE STM32_MCO2PRE_DIV5 | ||
67 | #define STM32_I2SSRC STM32_I2SSRC_CKIN | ||
68 | #define STM32_PLLI2SN_VALUE 192 | ||
69 | #define STM32_PLLI2SR_VALUE 5 | ||
70 | |||
71 | /* | ||
72 | * IRQ system settings. | ||
73 | */ | ||
74 | #define STM32_IRQ_EXTI0_PRIORITY 6 | ||
75 | #define STM32_IRQ_EXTI1_PRIORITY 6 | ||
76 | #define STM32_IRQ_EXTI2_PRIORITY 6 | ||
77 | #define STM32_IRQ_EXTI3_PRIORITY 6 | ||
78 | #define STM32_IRQ_EXTI4_PRIORITY 6 | ||
79 | #define STM32_IRQ_EXTI5_9_PRIORITY 6 | ||
80 | #define STM32_IRQ_EXTI10_15_PRIORITY 6 | ||
81 | #define STM32_IRQ_EXTI16_PRIORITY 6 | ||
82 | #define STM32_IRQ_EXTI17_PRIORITY 15 | ||
83 | #define STM32_IRQ_EXTI18_PRIORITY 6 | ||
84 | #define STM32_IRQ_EXTI19_PRIORITY 6 | ||
85 | #define STM32_IRQ_EXTI20_PRIORITY 6 | ||
86 | #define STM32_IRQ_EXTI21_PRIORITY 15 | ||
87 | #define STM32_IRQ_EXTI22_PRIORITY 15 | ||
88 | |||
89 | /* | ||
90 | * ADC driver system settings. | ||
91 | */ | ||
92 | #define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV4 | ||
93 | #define STM32_ADC_USE_ADC1 FALSE | ||
94 | #define STM32_ADC_USE_ADC2 FALSE | ||
95 | #define STM32_ADC_USE_ADC3 FALSE | ||
96 | #define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4) | ||
97 | #define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) | ||
98 | #define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(2, 1) | ||
99 | #define STM32_ADC_ADC1_DMA_PRIORITY 2 | ||
100 | #define STM32_ADC_ADC2_DMA_PRIORITY 2 | ||
101 | #define STM32_ADC_ADC3_DMA_PRIORITY 2 | ||
102 | #define STM32_ADC_IRQ_PRIORITY 6 | ||
103 | #define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 6 | ||
104 | #define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 6 | ||
105 | #define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 6 | ||
106 | |||
107 | /* | ||
108 | * CAN driver system settings. | ||
109 | */ | ||
110 | #define STM32_CAN_USE_CAN1 FALSE | ||
111 | #define STM32_CAN_USE_CAN2 FALSE | ||
112 | #define STM32_CAN_CAN1_IRQ_PRIORITY 11 | ||
113 | #define STM32_CAN_CAN2_IRQ_PRIORITY 11 | ||
114 | |||
115 | /* | ||
116 | * DAC driver system settings. | ||
117 | */ | ||
118 | #define STM32_DAC_DUAL_MODE FALSE | ||
119 | #define STM32_DAC_USE_DAC1_CH1 FALSE | ||
120 | #define STM32_DAC_USE_DAC1_CH2 FALSE | ||
121 | #define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10 | ||
122 | #define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10 | ||
123 | #define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2 | ||
124 | #define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2 | ||
125 | #define STM32_DAC_DAC1_CH1_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) | ||
126 | #define STM32_DAC_DAC1_CH2_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) | ||
127 | |||
128 | /* | ||
129 | * GPT driver system settings. | ||
130 | */ | ||
131 | #define STM32_GPT_USE_TIM1 FALSE | ||
132 | #define STM32_GPT_USE_TIM2 FALSE | ||
133 | #define STM32_GPT_USE_TIM3 FALSE | ||
134 | #define STM32_GPT_USE_TIM4 FALSE | ||
135 | #define STM32_GPT_USE_TIM5 FALSE | ||
136 | #define STM32_GPT_USE_TIM6 FALSE | ||
137 | #define STM32_GPT_USE_TIM7 FALSE | ||
138 | #define STM32_GPT_USE_TIM8 FALSE | ||
139 | #define STM32_GPT_USE_TIM9 FALSE | ||
140 | #define STM32_GPT_USE_TIM11 FALSE | ||
141 | #define STM32_GPT_USE_TIM12 FALSE | ||
142 | #define STM32_GPT_USE_TIM14 FALSE | ||
143 | #define STM32_GPT_TIM1_IRQ_PRIORITY 7 | ||
144 | #define STM32_GPT_TIM2_IRQ_PRIORITY 7 | ||
145 | #define STM32_GPT_TIM3_IRQ_PRIORITY 7 | ||
146 | #define STM32_GPT_TIM4_IRQ_PRIORITY 7 | ||
147 | #define STM32_GPT_TIM5_IRQ_PRIORITY 7 | ||
148 | #define STM32_GPT_TIM6_IRQ_PRIORITY 7 | ||
149 | #define STM32_GPT_TIM7_IRQ_PRIORITY 7 | ||
150 | #define STM32_GPT_TIM8_IRQ_PRIORITY 7 | ||
151 | #define STM32_GPT_TIM9_IRQ_PRIORITY 7 | ||
152 | #define STM32_GPT_TIM11_IRQ_PRIORITY 7 | ||
153 | #define STM32_GPT_TIM12_IRQ_PRIORITY 7 | ||
154 | #define STM32_GPT_TIM14_IRQ_PRIORITY 7 | ||
155 | |||
156 | /* | ||
157 | * I2C driver system settings. | ||
158 | */ | ||
159 | #define STM32_I2C_USE_I2C1 FALSE | ||
160 | #define STM32_I2C_USE_I2C2 FALSE | ||
161 | #define STM32_I2C_USE_I2C3 FALSE | ||
162 | #define STM32_I2C_BUSY_TIMEOUT 50 | ||
163 | #define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) | ||
164 | #define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) | ||
165 | #define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) | ||
166 | #define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) | ||
167 | #define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) | ||
168 | #define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) | ||
169 | #define STM32_I2C_I2C1_IRQ_PRIORITY 5 | ||
170 | #define STM32_I2C_I2C2_IRQ_PRIORITY 5 | ||
171 | #define STM32_I2C_I2C3_IRQ_PRIORITY 5 | ||
172 | #define STM32_I2C_I2C1_DMA_PRIORITY 3 | ||
173 | #define STM32_I2C_I2C2_DMA_PRIORITY 3 | ||
174 | #define STM32_I2C_I2C3_DMA_PRIORITY 3 | ||
175 | #define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") | ||
176 | |||
177 | /* | ||
178 | * I2S driver system settings. | ||
179 | */ | ||
180 | #define STM32_I2S_USE_SPI2 FALSE | ||
181 | #define STM32_I2S_USE_SPI3 FALSE | ||
182 | #define STM32_I2S_SPI2_IRQ_PRIORITY 10 | ||
183 | #define STM32_I2S_SPI3_IRQ_PRIORITY 10 | ||
184 | #define STM32_I2S_SPI2_DMA_PRIORITY 1 | ||
185 | #define STM32_I2S_SPI3_DMA_PRIORITY 1 | ||
186 | #define STM32_I2S_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) | ||
187 | #define STM32_I2S_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) | ||
188 | #define STM32_I2S_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) | ||
189 | #define STM32_I2S_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) | ||
190 | #define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure") | ||
191 | |||
192 | /* | ||
193 | * ICU driver system settings. | ||
194 | */ | ||
195 | #define STM32_ICU_USE_TIM1 FALSE | ||
196 | #define STM32_ICU_USE_TIM2 FALSE | ||
197 | #define STM32_ICU_USE_TIM3 FALSE | ||
198 | #define STM32_ICU_USE_TIM4 FALSE | ||
199 | #define STM32_ICU_USE_TIM5 FALSE | ||
200 | #define STM32_ICU_USE_TIM8 FALSE | ||
201 | #define STM32_ICU_USE_TIM9 FALSE | ||
202 | #define STM32_ICU_TIM1_IRQ_PRIORITY 7 | ||
203 | #define STM32_ICU_TIM2_IRQ_PRIORITY 7 | ||
204 | #define STM32_ICU_TIM3_IRQ_PRIORITY 7 | ||
205 | #define STM32_ICU_TIM4_IRQ_PRIORITY 7 | ||
206 | #define STM32_ICU_TIM5_IRQ_PRIORITY 7 | ||
207 | #define STM32_ICU_TIM8_IRQ_PRIORITY 7 | ||
208 | #define STM32_ICU_TIM9_IRQ_PRIORITY 7 | ||
209 | |||
210 | /* | ||
211 | * MAC driver system settings. | ||
212 | */ | ||
213 | #define STM32_MAC_TRANSMIT_BUFFERS 2 | ||
214 | #define STM32_MAC_RECEIVE_BUFFERS 4 | ||
215 | #define STM32_MAC_BUFFERS_SIZE 1522 | ||
216 | #define STM32_MAC_PHY_TIMEOUT 100 | ||
217 | #define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE | ||
218 | #define STM32_MAC_ETH1_IRQ_PRIORITY 13 | ||
219 | #define STM32_MAC_IP_CHECKSUM_OFFLOAD 0 | ||
220 | |||
221 | /* | ||
222 | * PWM driver system settings. | ||
223 | */ | ||
224 | #define STM32_PWM_USE_ADVANCED FALSE | ||
225 | #define STM32_PWM_USE_TIM1 FALSE | ||
226 | #define STM32_PWM_USE_TIM2 FALSE | ||
227 | #define STM32_PWM_USE_TIM3 FALSE | ||
228 | #define STM32_PWM_USE_TIM4 FALSE | ||
229 | #define STM32_PWM_USE_TIM5 FALSE | ||
230 | #define STM32_PWM_USE_TIM8 FALSE | ||
231 | #define STM32_PWM_USE_TIM9 FALSE | ||
232 | #define STM32_PWM_TIM1_IRQ_PRIORITY 7 | ||
233 | #define STM32_PWM_TIM2_IRQ_PRIORITY 7 | ||
234 | #define STM32_PWM_TIM3_IRQ_PRIORITY 7 | ||
235 | #define STM32_PWM_TIM4_IRQ_PRIORITY 7 | ||
236 | #define STM32_PWM_TIM5_IRQ_PRIORITY 7 | ||
237 | #define STM32_PWM_TIM8_IRQ_PRIORITY 7 | ||
238 | #define STM32_PWM_TIM9_IRQ_PRIORITY 7 | ||
239 | |||
240 | /* | ||
241 | * RTC driver system settings. | ||
242 | */ | ||
243 | #define STM32_RTC_PRESA_VALUE 32 | ||
244 | #define STM32_RTC_PRESS_VALUE 1024 | ||
245 | #define STM32_RTC_CR_INIT 0 | ||
246 | #define STM32_RTC_TAMPCR_INIT 0 | ||
247 | |||
248 | /* | ||
249 | * SDC driver system settings. | ||
250 | */ | ||
251 | #define STM32_SDC_SDIO_DMA_PRIORITY 3 | ||
252 | #define STM32_SDC_SDIO_IRQ_PRIORITY 9 | ||
253 | #define STM32_SDC_WRITE_TIMEOUT_MS 1000 | ||
254 | #define STM32_SDC_READ_TIMEOUT_MS 1000 | ||
255 | #define STM32_SDC_CLOCK_ACTIVATION_DELAY 10 | ||
256 | #define STM32_SDC_SDIO_UNALIGNED_SUPPORT TRUE | ||
257 | #define STM32_SDC_SDIO_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) | ||
258 | |||
259 | /* | ||
260 | * SERIAL driver system settings. | ||
261 | */ | ||
262 | #define STM32_SERIAL_USE_USART1 FALSE | ||
263 | #define STM32_SERIAL_USE_USART2 FALSE | ||
264 | #define STM32_SERIAL_USE_USART3 FALSE | ||
265 | #define STM32_SERIAL_USE_UART4 FALSE | ||
266 | #define STM32_SERIAL_USE_UART5 FALSE | ||
267 | #define STM32_SERIAL_USE_USART6 FALSE | ||
268 | #define STM32_SERIAL_USART1_PRIORITY 12 | ||
269 | #define STM32_SERIAL_USART2_PRIORITY 12 | ||
270 | #define STM32_SERIAL_USART3_PRIORITY 12 | ||
271 | #define STM32_SERIAL_UART4_PRIORITY 12 | ||
272 | #define STM32_SERIAL_UART5_PRIORITY 12 | ||
273 | #define STM32_SERIAL_USART6_PRIORITY 12 | ||
274 | |||
275 | /* | ||
276 | * SPI driver system settings. | ||
277 | */ | ||
278 | #define STM32_SPI_USE_SPI1 FALSE | ||
279 | #define STM32_SPI_USE_SPI2 FALSE | ||
280 | #define STM32_SPI_USE_SPI3 FALSE | ||
281 | #define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) | ||
282 | #define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) | ||
283 | #define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) | ||
284 | #define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) | ||
285 | #define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) | ||
286 | #define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) | ||
287 | #define STM32_SPI_SPI1_DMA_PRIORITY 1 | ||
288 | #define STM32_SPI_SPI2_DMA_PRIORITY 1 | ||
289 | #define STM32_SPI_SPI3_DMA_PRIORITY 1 | ||
290 | #define STM32_SPI_SPI1_IRQ_PRIORITY 10 | ||
291 | #define STM32_SPI_SPI2_IRQ_PRIORITY 10 | ||
292 | #define STM32_SPI_SPI3_IRQ_PRIORITY 10 | ||
293 | #define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") | ||
294 | |||
295 | /* | ||
296 | * ST driver system settings. | ||
297 | */ | ||
298 | #define STM32_ST_IRQ_PRIORITY 8 | ||
299 | #define STM32_ST_USE_TIMER 2 | ||
300 | |||
301 | /* | ||
302 | * UART driver system settings. | ||
303 | */ | ||
304 | #define STM32_UART_USE_USART1 FALSE | ||
305 | #define STM32_UART_USE_USART2 FALSE | ||
306 | #define STM32_UART_USE_USART3 FALSE | ||
307 | #define STM32_UART_USE_UART4 FALSE | ||
308 | #define STM32_UART_USE_UART5 FALSE | ||
309 | #define STM32_UART_USE_USART6 FALSE | ||
310 | #define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) | ||
311 | #define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) | ||
312 | #define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) | ||
313 | #define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) | ||
314 | #define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 1) | ||
315 | #define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) | ||
316 | #define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) | ||
317 | #define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) | ||
318 | #define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) | ||
319 | #define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) | ||
320 | #define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) | ||
321 | #define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) | ||
322 | #define STM32_UART_USART1_IRQ_PRIORITY 12 | ||
323 | #define STM32_UART_USART2_IRQ_PRIORITY 12 | ||
324 | #define STM32_UART_USART3_IRQ_PRIORITY 12 | ||
325 | #define STM32_UART_UART4_IRQ_PRIORITY 12 | ||
326 | #define STM32_UART_UART5_IRQ_PRIORITY 12 | ||
327 | #define STM32_UART_USART6_IRQ_PRIORITY 12 | ||
328 | #define STM32_UART_USART1_DMA_PRIORITY 0 | ||
329 | #define STM32_UART_USART2_DMA_PRIORITY 0 | ||
330 | #define STM32_UART_USART3_DMA_PRIORITY 0 | ||
331 | #define STM32_UART_UART4_DMA_PRIORITY 0 | ||
332 | #define STM32_UART_UART5_DMA_PRIORITY 0 | ||
333 | #define STM32_UART_USART6_DMA_PRIORITY 0 | ||
334 | #define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure") | ||
335 | |||
336 | /* | ||
337 | * USB driver system settings. | ||
338 | */ | ||
339 | #define STM32_USB_USE_OTG1 TRUE | ||
340 | #define STM32_USB_USE_OTG2 FALSE | ||
341 | #define STM32_USB_OTG1_IRQ_PRIORITY 14 | ||
342 | #define STM32_USB_OTG2_IRQ_PRIORITY 14 | ||
343 | #define STM32_USB_OTG1_RX_FIFO_SIZE 512 | ||
344 | #define STM32_USB_OTG2_RX_FIFO_SIZE 1024 | ||
345 | #define STM32_USB_HOST_WAKEUP_DURATION 2 | ||
346 | |||
347 | #define STM32_USB_OTG_THREAD_PRIO NORMALPRIO+1 | ||
348 | #define STM32_USB_OTG_THREAD_STACK_SIZE 128 | ||
349 | |||
350 | /* | ||
351 | * WDG driver system settings. | ||
352 | */ | ||
353 | #define STM32_WDG_USE_IWDG FALSE | ||
354 | |||
355 | #endif /* MCUCONF_H */ | ||
diff --git a/platforms/chibios/boards/QMK_PROTON_C/configs/config.h b/platforms/chibios/boards/QMK_PROTON_C/configs/config.h index a73f0c0b4..fa1a73c35 100644 --- a/platforms/chibios/boards/QMK_PROTON_C/configs/config.h +++ b/platforms/chibios/boards/QMK_PROTON_C/configs/config.h | |||
@@ -18,3 +18,12 @@ | |||
18 | #ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP | 18 | #ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP |
19 | # define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE | 19 | # define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE |
20 | #endif | 20 | #endif |
21 | |||
22 | #ifdef CONVERT_TO_PROTON_C | ||
23 | # ifndef I2C1_SDA_PIN | ||
24 | # define I2C1_SDA_PIN D1 | ||
25 | # endif | ||
26 | # ifndef I2C1_SCL_PIN | ||
27 | # define I2C1_SCL_PIN D0 | ||
28 | # endif | ||
29 | #endif | ||
diff --git a/platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk b/platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk new file mode 100644 index 000000000..960fc2678 --- /dev/null +++ b/platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk | |||
@@ -0,0 +1,9 @@ | |||
1 | # List of all the board related files. | ||
2 | BOARDSRC = ${CHIBIOS_CONTRIB}/os/hal/boards/SIPEED_LONGAN_NANO/board.c | ||
3 | |||
4 | # Required include directories | ||
5 | BOARDINC = ${CHIBIOS_CONTRIB}/os/hal/boards/SIPEED_LONGAN_NANO | ||
6 | |||
7 | # Shared variables | ||
8 | ALLCSRC += $(BOARDSRC) | ||
9 | ALLINC += $(BOARDINC) | ||
diff --git a/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h new file mode 100644 index 000000000..6e5adb0fe --- /dev/null +++ b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* Copyright 2021 QMK | ||
2 | * | ||
3 | * This program is free software: you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation, either version 2 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | /* To compile the ChibiOS syscall stubs with picolibc | ||
18 | * the _reent struct has to be defined. */ | ||
19 | #if !defined(_FROM_ASM_) && defined(USE_PICOLIBC) | ||
20 | struct _reent; | ||
21 | #endif | ||
22 | |||
23 | #include_next <chconf.h> \ No newline at end of file | ||
diff --git a/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h new file mode 100644 index 000000000..ab086567e --- /dev/null +++ b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
3 | ChibiOS - Copyright (C) 2021 Stefan Kerkmann | ||
4 | |||
5 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | you may not use this file except in compliance with the License. | ||
7 | You may obtain a copy of the License at | ||
8 | |||
9 | http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | |||
11 | Unless required by applicable law or agreed to in writing, software | ||
12 | distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | See the License for the specific language governing permissions and | ||
15 | limitations under the License. | ||
16 | */ | ||
17 | |||
18 | #pragma once | ||
19 | |||
20 | #define GD32VF103_MCUCONF | ||
21 | #define GD32VF103CB | ||
22 | |||
23 | /* | ||
24 | * GD32VF103 drivers configuration. | ||
25 | * The following settings override the default settings present in | ||
26 | * the various device driver implementation headers. | ||
27 | * Note that the settings for each driver only have effect if the whole | ||
28 | * driver is enabled in halconf.h. | ||
29 | * | ||
30 | * IRQ priorities: | ||
31 | * 0...15 Lowest...Highest. | ||
32 | * | ||
33 | * DMA priorities: | ||
34 | * 0...3 Lowest...Highest. | ||
35 | */ | ||
36 | |||
37 | /* | ||
38 | * HAL driver system settings. | ||
39 | */ | ||
40 | |||
41 | #if defined(OVERCLOCK_120MHZ) | ||
42 | /* (8MHz / 2) * 30 = 120MHz Sysclock */ | ||
43 | #define GD32_ALLOW_120MHZ_SYSCLK | ||
44 | #define GD32_PLLMF_VALUE 30 | ||
45 | #define GD32_USBFSPSC GD32_USBFSPSC_DIV2P5 | ||
46 | #else | ||
47 | /* (8MHz / 2) * 24 = 96MHz Sysclock */ | ||
48 | #define GD32_PLLMF_VALUE 24 | ||
49 | #define GD32_USBFSPSC GD32_USBFSPSC_DIV2 | ||
50 | #endif | ||
51 | |||
52 | #define GD32_NO_INIT FALSE | ||
53 | #define GD32_IRC8M_ENABLED TRUE | ||
54 | #define GD32_IRC40K_ENABLED FALSE | ||
55 | #define GD32_HXTAL_ENABLED TRUE | ||
56 | #define GD32_LXTAL_ENABLED FALSE | ||
57 | #define GD32_SCS GD32_SCS_PLL | ||
58 | #define GD32_PLLSEL GD32_PLLSEL_PREDV0 | ||
59 | #define GD32_PREDV0SEL GD32_PREDV0SEL_HXTAL | ||
60 | #define GD32_PREDV0_VALUE 2 | ||
61 | #define GD32_PREDV1_VALUE 2 | ||
62 | #define GD32_PLL1MF_VALUE 14 | ||
63 | #define GD32_PLL2MF_VALUE 13 | ||
64 | #define GD32_AHBPSC GD32_AHBPSC_DIV1 | ||
65 | #define GD32_APB1PSC GD32_APB1PSC_DIV2 | ||
66 | #define GD32_APB2PSC GD32_APB2PSC_DIV1 | ||
67 | #define GD32_ADCPSC GD32_ADCPSC_DIV16 | ||
68 | #define GD32_USB_CLOCK_REQUIRED TRUE | ||
69 | #define GD32_I2S_CLOCK_REQUIRED FALSE | ||
70 | #define GD32_CKOUT0SEL GD32_CKOUT0SEL_NOCLOCK | ||
71 | #define GD32_RTCSRC GD32_RTCSRC_NOCLOCK | ||
72 | #define GD32_PVD_ENABLE FALSE | ||
73 | #define GD32_LVDT GD32_LVDT_LEV0 | ||
74 | |||
75 | /* | ||
76 | * ECLIC system settings. | ||
77 | */ | ||
78 | #define ECLIC_TRIGGER_DEFAULT ECLIC_POSTIVE_EDGE_TRIGGER | ||
79 | #define ECLIC_DMA_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
80 | |||
81 | /* | ||
82 | * IRQ system settings. | ||
83 | */ | ||
84 | #define GD32_IRQ_EXTI0_PRIORITY 6 | ||
85 | #define GD32_IRQ_EXTI1_PRIORITY 6 | ||
86 | #define GD32_IRQ_EXTI2_PRIORITY 6 | ||
87 | #define GD32_IRQ_EXTI3_PRIORITY 6 | ||
88 | #define GD32_IRQ_EXTI4_PRIORITY 6 | ||
89 | #define GD32_IRQ_EXTI5_9_PRIORITY 6 | ||
90 | #define GD32_IRQ_EXTI10_15_PRIORITY 6 | ||
91 | #define GD32_IRQ_EXTI0_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
92 | #define GD32_IRQ_EXTI1_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
93 | #define GD32_IRQ_EXTI2_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
94 | #define GD32_IRQ_EXTI3_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
95 | #define GD32_IRQ_EXTI4_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
96 | #define GD32_IRQ_EXTI5_9_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
97 | #define GD32_IRQ_EXTI10_15_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
98 | |||
99 | /* | ||
100 | * ADC driver system settings. | ||
101 | */ | ||
102 | #define GD32_ADC_USE_ADC0 FALSE | ||
103 | #define GD32_ADC_ADC0_DMA_PRIORITY 2 | ||
104 | #define GD32_ADC_ADC0_IRQ_PRIORITY 6 | ||
105 | |||
106 | /* | ||
107 | * CAN driver system settings. | ||
108 | */ | ||
109 | #define GD32_CAN_USE_CAN0 FALSE | ||
110 | #define GD32_CAN_CAN0_IRQ_PRIORITY 11 | ||
111 | #define GD32_CAN_USE_CAN1 FALSE | ||
112 | #define GD32_CAN_CAN1_IRQ_PRIORITY 11 | ||
113 | #define GD32_CAN_CAN0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
114 | #define GD32_CAN_CAN1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
115 | |||
116 | /* | ||
117 | * CRC driver system settings. | ||
118 | */ | ||
119 | #define GD32_CRC_USE_CRC0 FALSE | ||
120 | #define GD32_CRC_CRC0_DMA_IRQ_PRIORITY 14 | ||
121 | #define GD32_CRC_CRC0_DMA_PRIORITY 2 | ||
122 | #define GD32_CRC_CRC0_DMA_STREAM GD32_DMA_STREAM_ID(0, 0) | ||
123 | #define CRC_USE_DMA FALSE | ||
124 | #define CRCSW_USE_CRC1 FALSE | ||
125 | #define CRCSW_CRC32_TABLE FALSE | ||
126 | #define CRCSW_CRC16_TABLE FALSE | ||
127 | #define CRCSW_PROGRAMMABLE FALSE | ||
128 | |||
129 | /* | ||
130 | * DAC driver system settings. | ||
131 | */ | ||
132 | #define GD32_DAC_USE_DAC_CH1 FALSE | ||
133 | #define GD32_DAC_USE_DAC_CH2 FALSE | ||
134 | |||
135 | /* | ||
136 | * GPT driver system settings. | ||
137 | */ | ||
138 | #define GD32_GPT_USE_TIM0 FALSE | ||
139 | #define GD32_GPT_USE_TIM1 FALSE | ||
140 | #define GD32_GPT_USE_TIM2 FALSE | ||
141 | #define GD32_GPT_USE_TIM3 FALSE | ||
142 | #define GD32_GPT_USE_TIM4 FALSE | ||
143 | #define GD32_GPT_TIM0_IRQ_PRIORITY 7 | ||
144 | #define GD32_GPT_TIM1_IRQ_PRIORITY 7 | ||
145 | #define GD32_GPT_TIM2_IRQ_PRIORITY 7 | ||
146 | #define GD32_GPT_TIM3_IRQ_PRIORITY 7 | ||
147 | #define GD32_GPT_TIM4_IRQ_PRIORITY 7 | ||
148 | #define GD32_GPT_TIM0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
149 | #define GD32_GPT_TIM1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
150 | #define GD32_GPT_TIM2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
151 | #define GD32_GPT_TIM3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
152 | #define GD32_GPT_TIM4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
153 | #define GD32_GPT_TIM5_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
154 | #define GD32_GPT_TIM6_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
155 | |||
156 | /* | ||
157 | * I2S driver system settings. | ||
158 | */ | ||
159 | #define GD32_I2S_USE_SPI1 FALSE | ||
160 | #define GD32_I2S_USE_SPI2 FALSE | ||
161 | #define GD32_I2S_SPI1_IRQ_PRIORITY 10 | ||
162 | #define GD32_I2S_SPI2_IRQ_PRIORITY 10 | ||
163 | #define GD32_I2S_SPI1_DMA_PRIORITY 1 | ||
164 | #define GD32_I2S_SPI2_DMA_PRIORITY 1 | ||
165 | #define GD32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure") | ||
166 | |||
167 | /* | ||
168 | * I2C driver system settings. | ||
169 | */ | ||
170 | #define GD32_I2C_USE_I2C0 FALSE | ||
171 | #define GD32_I2C_USE_I2C1 FALSE | ||
172 | #define GD32_I2C_BUSY_TIMEOUT 50 | ||
173 | #define GD32_I2C_I2C0_IRQ_PRIORITY 10 | ||
174 | #define GD32_I2C_I2C1_IRQ_PRIORITY 5 | ||
175 | #define GD32_I2C_I2C0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
176 | #define GD32_I2C_I2C1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
177 | #define GD32_I2C_I2C0_DMA_PRIORITY 2 | ||
178 | #define GD32_I2C_I2C1_DMA_PRIORITY 2 | ||
179 | #define GD32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") | ||
180 | |||
181 | /* | ||
182 | * ICU driver system settings. | ||
183 | */ | ||
184 | #define GD32_ICU_USE_TIM0 FALSE | ||
185 | #define GD32_ICU_USE_TIM1 FALSE | ||
186 | #define GD32_ICU_USE_TIM2 FALSE | ||
187 | #define GD32_ICU_USE_TIM3 FALSE | ||
188 | #define GD32_ICU_USE_TIM4 FALSE | ||
189 | #define GD32_ICU_TIM0_IRQ_PRIORITY 7 | ||
190 | #define GD32_ICU_TIM1_IRQ_PRIORITY 7 | ||
191 | #define GD32_ICU_TIM2_IRQ_PRIORITY 7 | ||
192 | #define GD32_ICU_TIM3_IRQ_PRIORITY 7 | ||
193 | #define GD32_ICU_TIM4_IRQ_PRIORITY 7 | ||
194 | #define GD32_ICU_TIM0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
195 | #define GD32_ICU_TIM1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
196 | #define GD32_ICU_TIM2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
197 | #define GD32_ICU_TIM3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
198 | #define GD32_ICU_TIM4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
199 | |||
200 | /* | ||
201 | * PWM driver system settings. | ||
202 | */ | ||
203 | #define GD32_PWM_USE_ADVANCED FALSE | ||
204 | #define GD32_PWM_USE_TIM0 FALSE | ||
205 | #define GD32_PWM_USE_TIM1 FALSE | ||
206 | #define GD32_PWM_USE_TIM2 FALSE | ||
207 | #define GD32_PWM_USE_TIM3 FALSE | ||
208 | #define GD32_PWM_USE_TIM4 FALSE | ||
209 | #define GD32_PWM_TIM0_IRQ_PRIORITY 10 | ||
210 | #define GD32_PWM_TIM1_IRQ_PRIORITY 10 | ||
211 | #define GD32_PWM_TIM2_IRQ_PRIORITY 10 | ||
212 | #define GD32_PWM_TIM3_IRQ_PRIORITY 10 | ||
213 | #define GD32_PWM_TIM4_IRQ_PRIORITY 10 | ||
214 | #define GD32_PWM_TIM0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
215 | #define GD32_PWM_TIM1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
216 | #define GD32_PWM_TIM2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
217 | #define GD32_PWM_TIM3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
218 | #define GD32_PWM_TIM4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
219 | |||
220 | /* | ||
221 | * RTC driver system settings. | ||
222 | */ | ||
223 | #define GD32_RTC_IRQ_PRIORITY 15 | ||
224 | #define GD32_RTC_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
225 | |||
226 | /* | ||
227 | * SERIAL driver system settings. | ||
228 | */ | ||
229 | #define GD32_SERIAL_USE_USART0 FALSE | ||
230 | #define GD32_SERIAL_USE_USART1 FALSE | ||
231 | #define GD32_SERIAL_USE_USART2 FALSE | ||
232 | #define GD32_SERIAL_USE_UART3 FALSE | ||
233 | #define GD32_SERIAL_USE_UART4 FALSE | ||
234 | #define GD32_SERIAL_USART0_PRIORITY 10 | ||
235 | #define GD32_SERIAL_USART1_PRIORITY 10 | ||
236 | #define GD32_SERIAL_USART2_PRIORITY 10 | ||
237 | #define GD32_SERIAL_UART3_PRIORITY 10 | ||
238 | #define GD32_SERIAL_UART4_PRIORITY 10 | ||
239 | #define GD32_SERIAL_USART0_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
240 | #define GD32_SERIAL_USART1_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
241 | #define GD32_SERIAL_USART2_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
242 | #define GD32_SERIAL_UART3_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
243 | #define GD32_SERIAL_UART4_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
244 | |||
245 | /* | ||
246 | * SPI driver system settings. | ||
247 | */ | ||
248 | #define GD32_SPI_USE_SPI0 FALSE | ||
249 | #define GD32_SPI_USE_SPI1 FALSE | ||
250 | #define GD32_SPI_USE_SPI2 FALSE | ||
251 | #define GD32_SPI_SPI0_DMA_PRIORITY 1 | ||
252 | #define GD32_SPI_SPI1_DMA_PRIORITY 1 | ||
253 | #define GD32_SPI_SPI2_DMA_PRIORITY 1 | ||
254 | #define GD32_SPI_SPI0_IRQ_PRIORITY 10 | ||
255 | #define GD32_SPI_SPI1_IRQ_PRIORITY 10 | ||
256 | #define GD32_SPI_SPI2_IRQ_PRIORITY 10 | ||
257 | #define GD32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") | ||
258 | |||
259 | /* | ||
260 | * ST driver system settings. | ||
261 | */ | ||
262 | #define GD32_ST_IRQ_PRIORITY 10 | ||
263 | #define GD32_ST_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
264 | #define GD32_ST_USE_TIMER 1 | ||
265 | |||
266 | /* | ||
267 | * UART driver system settings. | ||
268 | */ | ||
269 | #define GD32_UART_USE_USART0 FALSE | ||
270 | #define GD32_UART_USE_USART1 FALSE | ||
271 | #define GD32_UART_USE_USART2 FALSE | ||
272 | #define GD32_UART_USE_UART3 FALSE | ||
273 | #define GD32_UART_USE_UART4 FALSE | ||
274 | #define GD32_UART_USART0_IRQ_PRIORITY 10 | ||
275 | #define GD32_UART_USART1_IRQ_PRIORITY 10 | ||
276 | #define GD32_UART_USART2_IRQ_PRIORITY 10 | ||
277 | #define GD32_UART_UART3_IRQ_PRIORITY 10 | ||
278 | #define GD32_UART_UART4_IRQ_PRIORITY 10 | ||
279 | #define GD32_UART_USART0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
280 | #define GD32_UART_USART1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
281 | #define GD32_UART_USART2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
282 | #define GD32_UART_UART3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
283 | #define GD32_UART_UART4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
284 | #define GD32_UART_USART0_DMA_PRIORITY 3 | ||
285 | #define GD32_UART_USART1_DMA_PRIORITY 3 | ||
286 | #define GD32_UART_USART2_DMA_PRIORITY 3 | ||
287 | #define GD32_UART_UART3_DMA_PRIORITY 3 | ||
288 | #define GD32_UART_UART4_DMA_PRIORITY 3 | ||
289 | #define GD32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure") | ||
290 | |||
291 | /* | ||
292 | * USB driver system settings. | ||
293 | */ | ||
294 | #define GD32_USB_USE_USBFS TRUE | ||
295 | #define GD32_USB_USBFS_IRQ_PRIORITY 10 | ||
296 | #define GD32_USB_USBFS_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
297 | #define GD32_USB_USBFS_RX_FIFO_SIZE 256 | ||
298 | |||
299 | /* | ||
300 | * WDG driver system settings. | ||
301 | */ | ||
302 | #define GD32_WDG_USE_FWDGT FALSE | ||
diff --git a/platforms/chibios/boards/common/ld/STM32F401xC.ld b/platforms/chibios/boards/common/ld/STM32F401xC.ld new file mode 100644 index 000000000..8fae66cec --- /dev/null +++ b/platforms/chibios/boards/common/ld/STM32F401xC.ld | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * STM32F401xC memory setup. | ||
19 | */ | ||
20 | MEMORY | ||
21 | { | ||
22 | flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */ | ||
23 | flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */ | ||
24 | flash2 (rx) : org = 0x08008000, len = 256k - 32k /* Sector 2..6 - Rest of firmware */ | ||
25 | flash3 (rx) : org = 0x00000000, len = 0 | ||
26 | flash4 (rx) : org = 0x00000000, len = 0 | ||
27 | flash5 (rx) : org = 0x00000000, len = 0 | ||
28 | flash6 (rx) : org = 0x00000000, len = 0 | ||
29 | flash7 (rx) : org = 0x00000000, len = 0 | ||
30 | ram0 (wx) : org = 0x20000000, len = 64k | ||
31 | ram1 (wx) : org = 0x00000000, len = 0 | ||
32 | ram2 (wx) : org = 0x00000000, len = 0 | ||
33 | ram3 (wx) : org = 0x00000000, len = 0 | ||
34 | ram4 (wx) : org = 0x00000000, len = 0 | ||
35 | ram5 (wx) : org = 0x00000000, len = 0 | ||
36 | ram6 (wx) : org = 0x00000000, len = 0 | ||
37 | ram7 (wx) : org = 0x00000000, len = 0 | ||
38 | } | ||
39 | |||
40 | /* For each data/text section two region are defined, a virtual region | ||
41 | and a load region (_LMA suffix).*/ | ||
42 | |||
43 | /* Flash region to be used for exception vectors.*/ | ||
44 | REGION_ALIAS("VECTORS_FLASH", flash0); | ||
45 | REGION_ALIAS("VECTORS_FLASH_LMA", flash0); | ||
46 | |||
47 | /* Flash region to be used for constructors and destructors.*/ | ||
48 | REGION_ALIAS("XTORS_FLASH", flash2); | ||
49 | REGION_ALIAS("XTORS_FLASH_LMA", flash2); | ||
50 | |||
51 | /* Flash region to be used for code text.*/ | ||
52 | REGION_ALIAS("TEXT_FLASH", flash2); | ||
53 | REGION_ALIAS("TEXT_FLASH_LMA", flash2); | ||
54 | |||
55 | /* Flash region to be used for read only data.*/ | ||
56 | REGION_ALIAS("RODATA_FLASH", flash2); | ||
57 | REGION_ALIAS("RODATA_FLASH_LMA", flash2); | ||
58 | |||
59 | /* Flash region to be used for various.*/ | ||
60 | REGION_ALIAS("VARIOUS_FLASH", flash2); | ||
61 | REGION_ALIAS("VARIOUS_FLASH_LMA", flash2); | ||
62 | |||
63 | /* Flash region to be used for RAM(n) initialization data.*/ | ||
64 | REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2); | ||
65 | |||
66 | /* RAM region to be used for Main stack. This stack accommodates the processing | ||
67 | of all exceptions and interrupts.*/ | ||
68 | REGION_ALIAS("MAIN_STACK_RAM", ram0); | ||
69 | |||
70 | /* RAM region to be used for the process stack. This is the stack used by | ||
71 | the main() function.*/ | ||
72 | REGION_ALIAS("PROCESS_STACK_RAM", ram0); | ||
73 | |||
74 | /* RAM region to be used for data segment.*/ | ||
75 | REGION_ALIAS("DATA_RAM", ram0); | ||
76 | REGION_ALIAS("DATA_RAM_LMA", flash2); | ||
77 | |||
78 | /* RAM region to be used for BSS segment.*/ | ||
79 | REGION_ALIAS("BSS_RAM", ram0); | ||
80 | |||
81 | /* RAM region to be used for the default heap.*/ | ||
82 | REGION_ALIAS("HEAP_RAM", ram0); | ||
83 | |||
84 | /* Generic rules inclusion.*/ | ||
85 | INCLUDE rules.ld | ||
diff --git a/platforms/chibios/boards/common/ld/STM32F401xE.ld b/platforms/chibios/boards/common/ld/STM32F401xE.ld new file mode 100644 index 000000000..69af7ed71 --- /dev/null +++ b/platforms/chibios/boards/common/ld/STM32F401xE.ld | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * STM32F401xE memory setup. | ||
19 | */ | ||
20 | MEMORY | ||
21 | { | ||
22 | flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */ | ||
23 | flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */ | ||
24 | flash2 (rx) : org = 0x08008000, len = 512k - 32k /* Sector 2..7 - Rest of firmware */ | ||
25 | flash3 (rx) : org = 0x00000000, len = 0 | ||
26 | flash4 (rx) : org = 0x00000000, len = 0 | ||
27 | flash5 (rx) : org = 0x00000000, len = 0 | ||
28 | flash6 (rx) : org = 0x00000000, len = 0 | ||
29 | flash7 (rx) : org = 0x00000000, len = 0 | ||
30 | ram0 (wx) : org = 0x20000000, len = 96k | ||
31 | ram1 (wx) : org = 0x00000000, len = 0 | ||
32 | ram2 (wx) : org = 0x00000000, len = 0 | ||
33 | ram3 (wx) : org = 0x00000000, len = 0 | ||
34 | ram4 (wx) : org = 0x00000000, len = 0 | ||
35 | ram5 (wx) : org = 0x00000000, len = 0 | ||
36 | ram6 (wx) : org = 0x00000000, len = 0 | ||
37 | ram7 (wx) : org = 0x00000000, len = 0 | ||
38 | } | ||
39 | |||
40 | /* For each data/text section two region are defined, a virtual region | ||
41 | and a load region (_LMA suffix).*/ | ||
42 | |||
43 | /* Flash region to be used for exception vectors.*/ | ||
44 | REGION_ALIAS("VECTORS_FLASH", flash0); | ||
45 | REGION_ALIAS("VECTORS_FLASH_LMA", flash0); | ||
46 | |||
47 | /* Flash region to be used for constructors and destructors.*/ | ||
48 | REGION_ALIAS("XTORS_FLASH", flash2); | ||
49 | REGION_ALIAS("XTORS_FLASH_LMA", flash2); | ||
50 | |||
51 | /* Flash region to be used for code text.*/ | ||
52 | REGION_ALIAS("TEXT_FLASH", flash2); | ||
53 | REGION_ALIAS("TEXT_FLASH_LMA", flash2); | ||
54 | |||
55 | /* Flash region to be used for read only data.*/ | ||
56 | REGION_ALIAS("RODATA_FLASH", flash2); | ||
57 | REGION_ALIAS("RODATA_FLASH_LMA", flash2); | ||
58 | |||
59 | /* Flash region to be used for various.*/ | ||
60 | REGION_ALIAS("VARIOUS_FLASH", flash2); | ||
61 | REGION_ALIAS("VARIOUS_FLASH_LMA", flash2); | ||
62 | |||
63 | /* Flash region to be used for RAM(n) initialization data.*/ | ||
64 | REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2); | ||
65 | |||
66 | /* RAM region to be used for Main stack. This stack accommodates the processing | ||
67 | of all exceptions and interrupts.*/ | ||
68 | REGION_ALIAS("MAIN_STACK_RAM", ram0); | ||
69 | |||
70 | /* RAM region to be used for the process stack. This is the stack used by | ||
71 | the main() function.*/ | ||
72 | REGION_ALIAS("PROCESS_STACK_RAM", ram0); | ||
73 | |||
74 | /* RAM region to be used for data segment.*/ | ||
75 | REGION_ALIAS("DATA_RAM", ram0); | ||
76 | REGION_ALIAS("DATA_RAM_LMA", flash2); | ||
77 | |||
78 | /* RAM region to be used for BSS segment.*/ | ||
79 | REGION_ALIAS("BSS_RAM", ram0); | ||
80 | |||
81 | /* RAM region to be used for the default heap.*/ | ||
82 | REGION_ALIAS("HEAP_RAM", ram0); | ||
83 | |||
84 | /* Generic rules inclusion.*/ | ||
85 | INCLUDE rules.ld | ||
diff --git a/platforms/chibios/boards/common/ld/STM32F405xG.ld b/platforms/chibios/boards/common/ld/STM32F405xG.ld new file mode 100644 index 000000000..b7d0baa21 --- /dev/null +++ b/platforms/chibios/boards/common/ld/STM32F405xG.ld | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * STM32F405xG memory setup. | ||
19 | * Note: Use of ram1 and ram2 is mutually exclusive with use of ram0. | ||
20 | */ | ||
21 | MEMORY | ||
22 | { | ||
23 | flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */ | ||
24 | flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */ | ||
25 | flash2 (rx) : org = 0x08008000, len = 1M - 32k /* Sector 2..6 - Rest of firmware */ | ||
26 | flash3 (rx) : org = 0x00000000, len = 0 | ||
27 | flash4 (rx) : org = 0x00000000, len = 0 | ||
28 | flash5 (rx) : org = 0x00000000, len = 0 | ||
29 | flash6 (rx) : org = 0x00000000, len = 0 | ||
30 | flash7 (rx) : org = 0x00000000, len = 0 | ||
31 | ram0 (wx) : org = 0x20000000, len = 128k /* SRAM1 + SRAM2 */ | ||
32 | ram1 (wx) : org = 0x20000000, len = 112k /* SRAM1 */ | ||
33 | ram2 (wx) : org = 0x2001C000, len = 16k /* SRAM2 */ | ||
34 | ram3 (wx) : org = 0x00000000, len = 0 | ||
35 | ram4 (wx) : org = 0x10000000, len = 64k /* CCM SRAM */ | ||
36 | ram5 (wx) : org = 0x40024000, len = 4k /* BCKP SRAM */ | ||
37 | ram6 (wx) : org = 0x00000000, len = 0 | ||
38 | ram7 (wx) : org = 0x00000000, len = 0 | ||
39 | } | ||
40 | |||
41 | /* For each data/text section two region are defined, a virtual region | ||
42 | and a load region (_LMA suffix).*/ | ||
43 | |||
44 | /* Flash region to be used for exception vectors.*/ | ||
45 | REGION_ALIAS("VECTORS_FLASH", flash0); | ||
46 | REGION_ALIAS("VECTORS_FLASH_LMA", flash0); | ||
47 | |||
48 | /* Flash region to be used for constructors and destructors.*/ | ||
49 | REGION_ALIAS("XTORS_FLASH", flash2); | ||
50 | REGION_ALIAS("XTORS_FLASH_LMA", flash2); | ||
51 | |||
52 | /* Flash region to be used for code text.*/ | ||
53 | REGION_ALIAS("TEXT_FLASH", flash2); | ||
54 | REGION_ALIAS("TEXT_FLASH_LMA", flash2); | ||
55 | |||
56 | /* Flash region to be used for read only data.*/ | ||
57 | REGION_ALIAS("RODATA_FLASH", flash2); | ||
58 | REGION_ALIAS("RODATA_FLASH_LMA", flash2); | ||
59 | |||
60 | /* Flash region to be used for various.*/ | ||
61 | REGION_ALIAS("VARIOUS_FLASH", flash2); | ||
62 | REGION_ALIAS("VARIOUS_FLASH_LMA", flash2); | ||
63 | |||
64 | /* Flash region to be used for RAM(n) initialization data.*/ | ||
65 | REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2); | ||
66 | |||
67 | /* RAM region to be used for Main stack. This stack accommodates the processing | ||
68 | of all exceptions and interrupts.*/ | ||
69 | REGION_ALIAS("MAIN_STACK_RAM", ram0); | ||
70 | |||
71 | /* RAM region to be used for the process stack. This is the stack used by | ||
72 | the main() function.*/ | ||
73 | REGION_ALIAS("PROCESS_STACK_RAM", ram0); | ||
74 | |||
75 | /* RAM region to be used for data segment.*/ | ||
76 | REGION_ALIAS("DATA_RAM", ram0); | ||
77 | REGION_ALIAS("DATA_RAM_LMA", flash2); | ||
78 | |||
79 | /* RAM region to be used for BSS segment.*/ | ||
80 | REGION_ALIAS("BSS_RAM", ram0); | ||
81 | |||
82 | /* RAM region to be used for the default heap.*/ | ||
83 | REGION_ALIAS("HEAP_RAM", ram0); | ||
84 | |||
85 | /* Generic rules inclusion.*/ | ||
86 | INCLUDE rules.ld | ||
diff --git a/platforms/chibios/boards/common/ld/STM32F411xE.ld b/platforms/chibios/boards/common/ld/STM32F411xE.ld new file mode 100644 index 000000000..aea8084b5 --- /dev/null +++ b/platforms/chibios/boards/common/ld/STM32F411xE.ld | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * STM32F411xE memory setup. | ||
19 | */ | ||
20 | MEMORY | ||
21 | { | ||
22 | flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */ | ||
23 | flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */ | ||
24 | flash2 (rx) : org = 0x08008000, len = 512k - 32k /* Sector 2..7 - Rest of firmware */ | ||
25 | flash3 (rx) : org = 0x00000000, len = 0 | ||
26 | flash4 (rx) : org = 0x00000000, len = 0 | ||
27 | flash5 (rx) : org = 0x00000000, len = 0 | ||
28 | flash6 (rx) : org = 0x00000000, len = 0 | ||
29 | flash7 (rx) : org = 0x00000000, len = 0 | ||
30 | ram0 (wx) : org = 0x20000000, len = 128k | ||
31 | ram1 (wx) : org = 0x00000000, len = 0 | ||
32 | ram2 (wx) : org = 0x00000000, len = 0 | ||
33 | ram3 (wx) : org = 0x00000000, len = 0 | ||
34 | ram4 (wx) : org = 0x00000000, len = 0 | ||
35 | ram5 (wx) : org = 0x00000000, len = 0 | ||
36 | ram6 (wx) : org = 0x00000000, len = 0 | ||
37 | ram7 (wx) : org = 0x00000000, len = 0 | ||
38 | } | ||
39 | |||
40 | /* For each data/text section two region are defined, a virtual region | ||
41 | and a load region (_LMA suffix).*/ | ||
42 | |||
43 | /* Flash region to be used for exception vectors.*/ | ||
44 | REGION_ALIAS("VECTORS_FLASH", flash0); | ||
45 | REGION_ALIAS("VECTORS_FLASH_LMA", flash0); | ||
46 | |||
47 | /* Flash region to be used for constructors and destructors.*/ | ||
48 | REGION_ALIAS("XTORS_FLASH", flash2); | ||
49 | REGION_ALIAS("XTORS_FLASH_LMA", flash2); | ||
50 | |||
51 | /* Flash region to be used for code text.*/ | ||
52 | REGION_ALIAS("TEXT_FLASH", flash2); | ||
53 | REGION_ALIAS("TEXT_FLASH_LMA", flash2); | ||
54 | |||
55 | /* Flash region to be used for read only data.*/ | ||
56 | REGION_ALIAS("RODATA_FLASH", flash2); | ||
57 | REGION_ALIAS("RODATA_FLASH_LMA", flash2); | ||
58 | |||
59 | /* Flash region to be used for various.*/ | ||
60 | REGION_ALIAS("VARIOUS_FLASH", flash2); | ||
61 | REGION_ALIAS("VARIOUS_FLASH_LMA", flash2); | ||
62 | |||
63 | /* Flash region to be used for RAM(n) initialization data.*/ | ||
64 | REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2); | ||
65 | |||
66 | /* RAM region to be used for Main stack. This stack accommodates the processing | ||
67 | of all exceptions and interrupts.*/ | ||
68 | REGION_ALIAS("MAIN_STACK_RAM", ram0); | ||
69 | |||
70 | /* RAM region to be used for the process stack. This is the stack used by | ||
71 | the main() function.*/ | ||
72 | REGION_ALIAS("PROCESS_STACK_RAM", ram0); | ||
73 | |||
74 | /* RAM region to be used for data segment.*/ | ||
75 | REGION_ALIAS("DATA_RAM", ram0); | ||
76 | REGION_ALIAS("DATA_RAM_LMA", flash2); | ||
77 | |||
78 | /* RAM region to be used for BSS segment.*/ | ||
79 | REGION_ALIAS("BSS_RAM", ram0); | ||
80 | |||
81 | /* RAM region to be used for the default heap.*/ | ||
82 | REGION_ALIAS("HEAP_RAM", ram0); | ||
83 | |||
84 | /* Generic rules inclusion.*/ | ||
85 | INCLUDE rules.ld | ||
diff --git a/platforms/chibios/drivers/analog.c b/platforms/chibios/drivers/analog.c index 8c476fcac..eb437665f 100644 --- a/platforms/chibios/drivers/analog.c +++ b/platforms/chibios/drivers/analog.c | |||
@@ -38,7 +38,7 @@ | |||
38 | // Otherwise assume V3 | 38 | // Otherwise assume V3 |
39 | #if defined(STM32F0XX) || defined(STM32L0XX) | 39 | #if defined(STM32F0XX) || defined(STM32L0XX) |
40 | # define USE_ADCV1 | 40 | # define USE_ADCV1 |
41 | #elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) | 41 | #elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(GD32VF103) |
42 | # define USE_ADCV2 | 42 | # define USE_ADCV2 |
43 | #endif | 43 | #endif |
44 | 44 | ||
@@ -75,7 +75,7 @@ | |||
75 | 75 | ||
76 | /* User configurable ADC options */ | 76 | /* User configurable ADC options */ |
77 | #ifndef ADC_COUNT | 77 | #ifndef ADC_COUNT |
78 | # if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) | 78 | # if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) || defined(GD32VF103) |
79 | # define ADC_COUNT 1 | 79 | # define ADC_COUNT 1 |
80 | # elif defined(STM32F3XX) | 80 | # elif defined(STM32F3XX) |
81 | # define ADC_COUNT 4 | 81 | # define ADC_COUNT 4 |
@@ -122,8 +122,8 @@ static ADCConversionGroup adcConversionGroup = { | |||
122 | .cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION, | 122 | .cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION, |
123 | .smpr = ADC_SAMPLING_RATE, | 123 | .smpr = ADC_SAMPLING_RATE, |
124 | #elif defined(USE_ADCV2) | 124 | #elif defined(USE_ADCV2) |
125 | # if !defined(STM32F1XX) | 125 | # if !defined(STM32F1XX) && !defined(GD32VF103) |
126 | .cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without... | 126 | .cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without... |
127 | # endif | 127 | # endif |
128 | .smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE), | 128 | .smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE), |
129 | .smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE), | 129 | .smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE), |
@@ -220,7 +220,7 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) { | |||
220 | case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 ); | 220 | case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 ); |
221 | case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 ); | 221 | case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 ); |
222 | # endif | 222 | # endif |
223 | #elif defined(STM32F1XX) | 223 | #elif defined(STM32F1XX) || defined(GD32VF103) |
224 | case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 ); | 224 | case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 ); |
225 | case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 ); | 225 | case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 ); |
226 | case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 ); | 226 | case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 ); |
diff --git a/platforms/chibios/drivers/audio_dac.h b/platforms/chibios/drivers/audio_dac.h new file mode 100644 index 000000000..07cd622ea --- /dev/null +++ b/platforms/chibios/drivers/audio_dac.h | |||
@@ -0,0 +1,126 @@ | |||
1 | /* Copyright 2019 Jack Humbert | ||
2 | * Copyright 2020 JohSchneider | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | #pragma once | ||
18 | |||
19 | #ifndef A4 | ||
20 | # define A4 PAL_LINE(GPIOA, 4) | ||
21 | #endif | ||
22 | #ifndef A5 | ||
23 | # define A5 PAL_LINE(GPIOA, 5) | ||
24 | #endif | ||
25 | |||
26 | /** | ||
27 | * Size of the dac_buffer arrays. All must be the same size. | ||
28 | */ | ||
29 | #define AUDIO_DAC_BUFFER_SIZE 256U | ||
30 | |||
31 | /** | ||
32 | * Highest value allowed sample value. | ||
33 | |||
34 | * since the DAC is limited to 12 bit, the absolute max is 0xfff = 4095U; | ||
35 | * lower values adjust the peak-voltage aka volume down. | ||
36 | * adjusting this value has only an effect on a sample-buffer whose values are | ||
37 | * are NOT pregenerated - see square-wave | ||
38 | */ | ||
39 | #ifndef AUDIO_DAC_SAMPLE_MAX | ||
40 | # define AUDIO_DAC_SAMPLE_MAX 4095U | ||
41 | #endif | ||
42 | |||
43 | #if !defined(AUDIO_DAC_SAMPLE_RATE) && !defined(AUDIO_MAX_SIMULTANEOUS_TONES) && !defined(AUDIO_DAC_QUALITY_VERY_LOW) && !defined(AUDIO_DAC_QUALITY_LOW) && !defined(AUDIO_DAC_QUALITY_HIGH) && !defined(AUDIO_DAC_QUALITY_VERY_HIGH) | ||
44 | # define AUDIO_DAC_QUALITY_SANE_MINIMUM | ||
45 | #endif | ||
46 | |||
47 | /** | ||
48 | * These presets allow you to quickly switch between quality settings for | ||
49 | * the DAC. The sample rate and maximum number of simultaneous tones roughly | ||
50 | * has an inverse relationship - slightly higher sample rates may be possible. | ||
51 | * | ||
52 | * NOTE: a high sample-rate results in a higher cpu-load, which might lead to | ||
53 | * (audible) discontinuities and/or starve other processes of cpu-time | ||
54 | * (like RGB-led back-lighting, ...) | ||
55 | */ | ||
56 | #ifdef AUDIO_DAC_QUALITY_VERY_LOW | ||
57 | # define AUDIO_DAC_SAMPLE_RATE 11025U | ||
58 | # define AUDIO_MAX_SIMULTANEOUS_TONES 8 | ||
59 | #endif | ||
60 | |||
61 | #ifdef AUDIO_DAC_QUALITY_LOW | ||
62 | # define AUDIO_DAC_SAMPLE_RATE 22050U | ||
63 | # define AUDIO_MAX_SIMULTANEOUS_TONES 4 | ||
64 | #endif | ||
65 | |||
66 | #ifdef AUDIO_DAC_QUALITY_HIGH | ||
67 | # define AUDIO_DAC_SAMPLE_RATE 44100U | ||
68 | # define AUDIO_MAX_SIMULTANEOUS_TONES 2 | ||
69 | #endif | ||
70 | |||
71 | #ifdef AUDIO_DAC_QUALITY_VERY_HIGH | ||
72 | # define AUDIO_DAC_SAMPLE_RATE 88200U | ||
73 | # define AUDIO_MAX_SIMULTANEOUS_TONES 1 | ||
74 | #endif | ||
75 | |||
76 | #ifdef AUDIO_DAC_QUALITY_SANE_MINIMUM | ||
77 | /* a sane-minimum config: with a trade-off between cpu-load and tone-range | ||
78 | * | ||
79 | * the (currently) highest defined note is NOTE_B8 with 7902Hz; if we now | ||
80 | * aim for an even even multiple of the buffer-size, we end up with: | ||
81 | * ( roundUptoPow2(highest note / AUDIO_DAC_BUFFER_SIZE) * nyquist-rate * AUDIO_DAC_BUFFER_SIZE) | ||
82 | * 7902/256 = 30.867 * 2 * 256 ~= 16384 | ||
83 | * which works out (but the 'scope shows some sampling artifacts with lower harmonics :-P) | ||
84 | */ | ||
85 | # define AUDIO_DAC_SAMPLE_RATE 16384U | ||
86 | # define AUDIO_MAX_SIMULTANEOUS_TONES 8 | ||
87 | #endif | ||
88 | |||
89 | /** | ||
90 | * Effective bit-rate of the DAC. 44.1khz is the standard for most audio - any | ||
91 | * lower will sacrifice perceptible audio quality. Any higher will limit the | ||
92 | * number of simultaneous tones. In most situations, a tenth (1/10) of the | ||
93 | * sample rate is where notes become unbearable. | ||
94 | */ | ||
95 | #ifndef AUDIO_DAC_SAMPLE_RATE | ||
96 | # define AUDIO_DAC_SAMPLE_RATE 44100U | ||
97 | #endif | ||
98 | |||
99 | /** | ||
100 | * The number of tones that can be played simultaneously. If too high a value | ||
101 | * is used here, the keyboard will freeze and glitch-out when that many tones | ||
102 | * are being played. | ||
103 | */ | ||
104 | #ifndef AUDIO_MAX_SIMULTANEOUS_TONES | ||
105 | # define AUDIO_MAX_SIMULTANEOUS_TONES 2 | ||
106 | #endif | ||
107 | |||
108 | /** | ||
109 | * The default value of the DAC when not playing anything. Certain hardware | ||
110 | * setups may require a high (AUDIO_DAC_SAMPLE_MAX) or low (0) value here. | ||
111 | * Since multiple added sine waves tend to oscillate around the midpoint, | ||
112 | * and possibly never/rarely reach either 0 of MAX, 1/2 MAX can be a | ||
113 | * reasonable default value. | ||
114 | */ | ||
115 | #ifndef AUDIO_DAC_OFF_VALUE | ||
116 | # define AUDIO_DAC_OFF_VALUE AUDIO_DAC_SAMPLE_MAX / 2 | ||
117 | #endif | ||
118 | |||
119 | #if AUDIO_DAC_OFF_VALUE > AUDIO_DAC_SAMPLE_MAX | ||
120 | # error "AUDIO_DAC: OFF_VALUE may not be larger than SAMPLE_MAX" | ||
121 | #endif | ||
122 | |||
123 | /** | ||
124 | *user overridable sample generation/processing | ||
125 | */ | ||
126 | uint16_t dac_value_generate(void); | ||
diff --git a/platforms/chibios/drivers/audio_dac_additive.c b/platforms/chibios/drivers/audio_dac_additive.c new file mode 100644 index 000000000..db304adb8 --- /dev/null +++ b/platforms/chibios/drivers/audio_dac_additive.c | |||
@@ -0,0 +1,335 @@ | |||
1 | /* Copyright 2016-2019 Jack Humbert | ||
2 | * Copyright 2020 JohSchneider | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "audio.h" | ||
19 | #include <ch.h> | ||
20 | #include <hal.h> | ||
21 | |||
22 | /* | ||
23 | Audio Driver: DAC | ||
24 | |||
25 | which utilizes the dac unit many STM32 are equipped with, to output a modulated waveform from samples stored in the dac_buffer_* array who are passed to the hardware through DMA | ||
26 | |||
27 | it is also possible to have a custom sample-LUT by implementing/overriding 'dac_value_generate' | ||
28 | |||
29 | this driver allows for multiple simultaneous tones to be played through one single channel by doing additive wave-synthesis | ||
30 | */ | ||
31 | |||
32 | #if !defined(AUDIO_PIN) | ||
33 | # error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC additive)' for available options." | ||
34 | #endif | ||
35 | #if defined(AUDIO_PIN_ALT) && !defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
36 | # pragma message "Audio feature: AUDIO_PIN_ALT set, but not AUDIO_PIN_ALT_AS_NEGATIVE - pin will be left unused; audio might still work though." | ||
37 | #endif | ||
38 | |||
39 | #if !defined(AUDIO_PIN_ALT) | ||
40 | // no ALT pin defined is valid, but the c-ifs below need some value set | ||
41 | # define AUDIO_PIN_ALT PAL_NOLINE | ||
42 | #endif | ||
43 | |||
44 | #if !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID) | ||
45 | # define AUDIO_DAC_SAMPLE_WAVEFORM_SINE | ||
46 | #endif | ||
47 | |||
48 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SINE | ||
49 | /* one full sine wave over [0,2*pi], but shifted up one amplitude and left pi/4; for the samples to start at 0 | ||
50 | */ | ||
51 | static const dacsample_t dac_buffer_sine[AUDIO_DAC_BUFFER_SIZE] = { | ||
52 | // 256 values, max 4095 | ||
53 | 0x0, 0x1, 0x2, 0x6, 0xa, 0xf, 0x16, 0x1e, 0x27, 0x32, 0x3d, 0x4a, 0x58, 0x67, 0x78, 0x89, 0x9c, 0xb0, 0xc5, 0xdb, 0xf2, 0x10a, 0x123, 0x13e, 0x159, 0x175, 0x193, 0x1b1, 0x1d1, 0x1f1, 0x212, 0x235, 0x258, 0x27c, 0x2a0, 0x2c6, 0x2ed, 0x314, 0x33c, 0x365, 0x38e, 0x3b8, 0x3e3, 0x40e, 0x43a, 0x467, 0x494, 0x4c2, 0x4f0, 0x51f, 0x54e, 0x57d, 0x5ad, 0x5dd, 0x60e, 0x63f, 0x670, 0x6a1, 0x6d3, 0x705, 0x737, 0x769, 0x79b, 0x7cd, 0x800, 0x832, 0x864, 0x896, 0x8c8, 0x8fa, 0x92c, 0x95e, 0x98f, 0x9c0, 0x9f1, 0xa22, 0xa52, 0xa82, 0xab1, 0xae0, 0xb0f, 0xb3d, 0xb6b, 0xb98, 0xbc5, 0xbf1, 0xc1c, 0xc47, 0xc71, 0xc9a, 0xcc3, 0xceb, 0xd12, 0xd39, 0xd5f, 0xd83, 0xda7, 0xdca, 0xded, 0xe0e, 0xe2e, 0xe4e, 0xe6c, 0xe8a, 0xea6, 0xec1, 0xedc, 0xef5, 0xf0d, 0xf24, 0xf3a, 0xf4f, 0xf63, 0xf76, 0xf87, 0xf98, 0xfa7, 0xfb5, 0xfc2, 0xfcd, 0xfd8, 0xfe1, 0xfe9, 0xff0, 0xff5, 0xff9, 0xffd, 0xffe, | ||
54 | 0xfff, 0xffe, 0xffd, 0xff9, 0xff5, 0xff0, 0xfe9, 0xfe1, 0xfd8, 0xfcd, 0xfc2, 0xfb5, 0xfa7, 0xf98, 0xf87, 0xf76, 0xf63, 0xf4f, 0xf3a, 0xf24, 0xf0d, 0xef5, 0xedc, 0xec1, 0xea6, 0xe8a, 0xe6c, 0xe4e, 0xe2e, 0xe0e, 0xded, 0xdca, 0xda7, 0xd83, 0xd5f, 0xd39, 0xd12, 0xceb, 0xcc3, 0xc9a, 0xc71, 0xc47, 0xc1c, 0xbf1, 0xbc5, 0xb98, 0xb6b, 0xb3d, 0xb0f, 0xae0, 0xab1, 0xa82, 0xa52, 0xa22, 0x9f1, 0x9c0, 0x98f, 0x95e, 0x92c, 0x8fa, 0x8c8, 0x896, 0x864, 0x832, 0x800, 0x7cd, 0x79b, 0x769, 0x737, 0x705, 0x6d3, 0x6a1, 0x670, 0x63f, 0x60e, 0x5dd, 0x5ad, 0x57d, 0x54e, 0x51f, 0x4f0, 0x4c2, 0x494, 0x467, 0x43a, 0x40e, 0x3e3, 0x3b8, 0x38e, 0x365, 0x33c, 0x314, 0x2ed, 0x2c6, 0x2a0, 0x27c, 0x258, 0x235, 0x212, 0x1f1, 0x1d1, 0x1b1, 0x193, 0x175, 0x159, 0x13e, 0x123, 0x10a, 0xf2, 0xdb, 0xc5, 0xb0, 0x9c, 0x89, 0x78, 0x67, 0x58, 0x4a, 0x3d, 0x32, 0x27, 0x1e, 0x16, 0xf, 0xa, 0x6, 0x2, 0x1}; | ||
55 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_SINE | ||
56 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE | ||
57 | static const dacsample_t dac_buffer_triangle[AUDIO_DAC_BUFFER_SIZE] = { | ||
58 | // 256 values, max 4095 | ||
59 | 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4a0, 0x4c0, 0x4e0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5a0, 0x5c0, 0x5e0, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6a0, 0x6c0, 0x6e0, 0x700, 0x720, 0x740, 0x760, 0x780, 0x7a0, 0x7c0, 0x7e0, 0x800, 0x81f, 0x83f, 0x85f, 0x87f, 0x89f, 0x8bf, 0x8df, 0x8ff, 0x91f, 0x93f, 0x95f, 0x97f, 0x99f, 0x9bf, 0x9df, 0x9ff, 0xa1f, 0xa3f, 0xa5f, 0xa7f, 0xa9f, 0xabf, 0xadf, 0xaff, 0xb1f, 0xb3f, 0xb5f, 0xb7f, 0xb9f, 0xbbf, 0xbdf, 0xbff, 0xc1f, 0xc3f, 0xc5f, 0xc7f, 0xc9f, 0xcbf, 0xcdf, 0xcff, 0xd1f, 0xd3f, 0xd5f, 0xd7f, 0xd9f, 0xdbf, 0xddf, 0xdff, 0xe1f, 0xe3f, 0xe5f, 0xe7f, 0xe9f, 0xebf, 0xedf, 0xeff, 0xf1f, 0xf3f, 0xf5f, 0xf7f, 0xf9f, 0xfbf, 0xfdf, | ||
60 | 0xfff, 0xfdf, 0xfbf, 0xf9f, 0xf7f, 0xf5f, 0xf3f, 0xf1f, 0xeff, 0xedf, 0xebf, 0xe9f, 0xe7f, 0xe5f, 0xe3f, 0xe1f, 0xdff, 0xddf, 0xdbf, 0xd9f, 0xd7f, 0xd5f, 0xd3f, 0xd1f, 0xcff, 0xcdf, 0xcbf, 0xc9f, 0xc7f, 0xc5f, 0xc3f, 0xc1f, 0xbff, 0xbdf, 0xbbf, 0xb9f, 0xb7f, 0xb5f, 0xb3f, 0xb1f, 0xaff, 0xadf, 0xabf, 0xa9f, 0xa7f, 0xa5f, 0xa3f, 0xa1f, 0x9ff, 0x9df, 0x9bf, 0x99f, 0x97f, 0x95f, 0x93f, 0x91f, 0x8ff, 0x8df, 0x8bf, 0x89f, 0x87f, 0x85f, 0x83f, 0x81f, 0x800, 0x7e0, 0x7c0, 0x7a0, 0x780, 0x760, 0x740, 0x720, 0x700, 0x6e0, 0x6c0, 0x6a0, 0x680, 0x660, 0x640, 0x620, 0x600, 0x5e0, 0x5c0, 0x5a0, 0x580, 0x560, 0x540, 0x520, 0x500, 0x4e0, 0x4c0, 0x4a0, 0x480, 0x460, 0x440, 0x420, 0x400, 0x3e0, 0x3c0, 0x3a0, 0x380, 0x360, 0x340, 0x320, 0x300, 0x2e0, 0x2c0, 0x2a0, 0x280, 0x260, 0x240, 0x220, 0x200, 0x1e0, 0x1c0, 0x1a0, 0x180, 0x160, 0x140, 0x120, 0x100, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20}; | ||
61 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE | ||
62 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE | ||
63 | static const dacsample_t dac_buffer_square[AUDIO_DAC_BUFFER_SIZE] = { | ||
64 | [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, // first and | ||
65 | [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, // second half | ||
66 | }; | ||
67 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE | ||
68 | /* | ||
69 | // four steps: 0, 1/3, 2/3 and 1 | ||
70 | static const dacsample_t dac_buffer_staircase[AUDIO_DAC_BUFFER_SIZE] = { | ||
71 | [0 ... AUDIO_DAC_BUFFER_SIZE/3 -1 ] = 0, | ||
72 | [AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE / 2 -1 ] = AUDIO_DAC_SAMPLE_MAX / 3, | ||
73 | [AUDIO_DAC_BUFFER_SIZE / 2 ... 3 * AUDIO_DAC_BUFFER_SIZE / 4 -1 ] = 2 * AUDIO_DAC_SAMPLE_MAX / 3, | ||
74 | [3 * AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE -1 ] = AUDIO_DAC_SAMPLE_MAX, | ||
75 | } | ||
76 | */ | ||
77 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID | ||
78 | static const dacsample_t dac_buffer_trapezoid[AUDIO_DAC_BUFFER_SIZE] = {0x0, 0x1f, 0x7f, 0xdf, 0x13f, 0x19f, 0x1ff, 0x25f, 0x2bf, 0x31f, 0x37f, 0x3df, 0x43f, 0x49f, 0x4ff, 0x55f, 0x5bf, 0x61f, 0x67f, 0x6df, 0x73f, 0x79f, 0x7ff, 0x85f, 0x8bf, 0x91f, 0x97f, 0x9df, 0xa3f, 0xa9f, 0xaff, 0xb5f, 0xbbf, 0xc1f, 0xc7f, 0xcdf, 0xd3f, 0xd9f, 0xdff, 0xe5f, 0xebf, 0xf1f, 0xf7f, 0xfdf, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, | ||
79 | 0xfff, 0xfdf, 0xf7f, 0xf1f, 0xebf, 0xe5f, 0xdff, 0xd9f, 0xd3f, 0xcdf, 0xc7f, 0xc1f, 0xbbf, 0xb5f, 0xaff, 0xa9f, 0xa3f, 0x9df, 0x97f, 0x91f, 0x8bf, 0x85f, 0x7ff, 0x79f, 0x73f, 0x6df, 0x67f, 0x61f, 0x5bf, 0x55f, 0x4ff, 0x49f, 0x43f, 0x3df, 0x37f, 0x31f, 0x2bf, 0x25f, 0x1ff, 0x19f, 0x13f, 0xdf, 0x7f, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; | ||
80 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID | ||
81 | |||
82 | static dacsample_t dac_buffer_empty[AUDIO_DAC_BUFFER_SIZE] = {AUDIO_DAC_OFF_VALUE}; | ||
83 | |||
84 | /* keep track of the sample position for for each frequency */ | ||
85 | static float dac_if[AUDIO_MAX_SIMULTANEOUS_TONES] = {0.0}; | ||
86 | |||
87 | static float active_tones_snapshot[AUDIO_MAX_SIMULTANEOUS_TONES] = {0, 0}; | ||
88 | static uint8_t active_tones_snapshot_length = 0; | ||
89 | |||
90 | typedef enum { | ||
91 | OUTPUT_SHOULD_START, | ||
92 | OUTPUT_RUN_NORMALLY, | ||
93 | // path 1: wait for zero, then change/update active tones | ||
94 | OUTPUT_TONES_CHANGED, | ||
95 | OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE, | ||
96 | // path 2: hardware should stop, wait for zero then turn output off = stop the timer | ||
97 | OUTPUT_SHOULD_STOP, | ||
98 | OUTPUT_REACHED_ZERO_BEFORE_OFF, | ||
99 | OUTPUT_OFF, | ||
100 | OUTPUT_OFF_1, | ||
101 | OUTPUT_OFF_2, // trailing off: giving the DAC two more conversion cycles until the AUDIO_DAC_OFF_VALUE reaches the output, then turn the timer off, which leaves the output at that level | ||
102 | number_of_output_states | ||
103 | } output_states_t; | ||
104 | output_states_t state = OUTPUT_OFF_2; | ||
105 | |||
106 | /** | ||
107 | * Generation of the waveform being passed to the callback. Declared weak so users | ||
108 | * can override it with their own wave-forms/noises. | ||
109 | */ | ||
110 | __attribute__((weak)) uint16_t dac_value_generate(void) { | ||
111 | // DAC is running/asking for values but snapshot length is zero -> must be playing a pause | ||
112 | if (active_tones_snapshot_length == 0) { | ||
113 | return AUDIO_DAC_OFF_VALUE; | ||
114 | } | ||
115 | |||
116 | /* doing additive wave synthesis over all currently playing tones = adding up | ||
117 | * sine-wave-samples for each frequency, scaled by the number of active tones | ||
118 | */ | ||
119 | uint16_t value = 0; | ||
120 | float frequency = 0.0f; | ||
121 | |||
122 | for (uint8_t i = 0; i < active_tones_snapshot_length; i++) { | ||
123 | /* Note: a user implementation does not have to rely on the active_tones_snapshot, but | ||
124 | * could directly query the active frequencies through audio_get_processed_frequency */ | ||
125 | frequency = active_tones_snapshot[i]; | ||
126 | |||
127 | dac_if[i] = dac_if[i] + ((frequency * AUDIO_DAC_BUFFER_SIZE) / AUDIO_DAC_SAMPLE_RATE) * 2 / 3; | ||
128 | /*Note: the 2/3 are necessary to get the correct frequencies on the | ||
129 | * DAC output (as measured with an oscilloscope), since the gpt | ||
130 | * timer runs with 3*AUDIO_DAC_SAMPLE_RATE; and the DAC callback | ||
131 | * is called twice per conversion.*/ | ||
132 | |||
133 | dac_if[i] = fmod(dac_if[i], AUDIO_DAC_BUFFER_SIZE); | ||
134 | |||
135 | // Wavetable generation/lookup | ||
136 | uint16_t dac_i = (uint16_t)dac_if[i]; | ||
137 | |||
138 | #if defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) | ||
139 | value += dac_buffer_sine[dac_i] / active_tones_snapshot_length; | ||
140 | #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) | ||
141 | value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length; | ||
142 | #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID) | ||
143 | value += dac_buffer_trapezoid[dac_i] / active_tones_snapshot_length; | ||
144 | #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) | ||
145 | value += dac_buffer_square[dac_i] / active_tones_snapshot_length; | ||
146 | #endif | ||
147 | /* | ||
148 | // SINE | ||
149 | value += dac_buffer_sine[dac_i] / active_tones_snapshot_length / 3; | ||
150 | // TRIANGLE | ||
151 | value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length / 3; | ||
152 | // SQUARE | ||
153 | value += dac_buffer_square[dac_i] / active_tones_snapshot_length / 3; | ||
154 | //NOTE: combination of these three wave-forms is more exemplary - and doesn't sound particularly good :-P | ||
155 | */ | ||
156 | |||
157 | // STAIRS (mostly usefully as test-pattern) | ||
158 | // value_avg = dac_buffer_staircase[dac_i] / active_tones_snapshot_length; | ||
159 | } | ||
160 | |||
161 | return value; | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * DAC streaming callback. Does all of the main computing for playing songs. | ||
166 | * | ||
167 | * Note: chibios calls this CB twice: during the 'half buffer event', and the 'full buffer event'. | ||
168 | */ | ||
169 | static void dac_end(DACDriver *dacp) { | ||
170 | dacsample_t *sample_p = (dacp)->samples; | ||
171 | |||
172 | // work on the other half of the buffer | ||
173 | if (dacIsBufferComplete(dacp)) { | ||
174 | sample_p += AUDIO_DAC_BUFFER_SIZE / 2; // 'half_index' | ||
175 | } | ||
176 | |||
177 | for (uint8_t s = 0; s < AUDIO_DAC_BUFFER_SIZE / 2; s++) { | ||
178 | if (OUTPUT_OFF <= state) { | ||
179 | sample_p[s] = AUDIO_DAC_OFF_VALUE; | ||
180 | continue; | ||
181 | } else { | ||
182 | sample_p[s] = dac_value_generate(); | ||
183 | } | ||
184 | |||
185 | /* zero crossing (or approach, whereas zero == DAC_OFF_VALUE, which can be configured to anything from 0 to DAC_SAMPLE_MAX) | ||
186 | * ============================*=*========================== AUDIO_DAC_SAMPLE_MAX | ||
187 | * * * | ||
188 | * * * | ||
189 | * --------------------------------------------------------- | ||
190 | * * * } AUDIO_DAC_SAMPLE_MAX/100 | ||
191 | * --------------------------------------------------------- AUDIO_DAC_OFF_VALUE | ||
192 | * * * } AUDIO_DAC_SAMPLE_MAX/100 | ||
193 | * --------------------------------------------------------- | ||
194 | * * | ||
195 | * * * | ||
196 | * * * | ||
197 | * =====*=*================================================= 0x0 | ||
198 | */ | ||
199 | if (((sample_p[s] + (AUDIO_DAC_SAMPLE_MAX / 100)) > AUDIO_DAC_OFF_VALUE) && // value approaches from below | ||
200 | (sample_p[s] < (AUDIO_DAC_OFF_VALUE + (AUDIO_DAC_SAMPLE_MAX / 100))) // or above | ||
201 | ) { | ||
202 | if ((OUTPUT_SHOULD_START == state) && (active_tones_snapshot_length > 0)) { | ||
203 | state = OUTPUT_RUN_NORMALLY; | ||
204 | } else if (OUTPUT_TONES_CHANGED == state) { | ||
205 | state = OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE; | ||
206 | } else if (OUTPUT_SHOULD_STOP == state) { | ||
207 | state = OUTPUT_REACHED_ZERO_BEFORE_OFF; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | // still 'ramping up', reset the output to OFF_VALUE until the generated values reach that value, to do a smooth handover | ||
212 | if (OUTPUT_SHOULD_START == state) { | ||
213 | sample_p[s] = AUDIO_DAC_OFF_VALUE; | ||
214 | } | ||
215 | |||
216 | if ((OUTPUT_SHOULD_START == state) || (OUTPUT_REACHED_ZERO_BEFORE_OFF == state) || (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state)) { | ||
217 | uint8_t active_tones = MIN(AUDIO_MAX_SIMULTANEOUS_TONES, audio_get_number_of_active_tones()); | ||
218 | active_tones_snapshot_length = 0; | ||
219 | // update the snapshot - once, and only on occasion that something changed; | ||
220 | // -> saves cpu cycles (?) | ||
221 | for (uint8_t i = 0; i < active_tones; i++) { | ||
222 | float freq = audio_get_processed_frequency(i); | ||
223 | if (freq > 0) { // disregard 'rest' notes, with valid frequency 0.0f; which would only lower the resulting waveform volume during the additive synthesis step | ||
224 | active_tones_snapshot[active_tones_snapshot_length++] = freq; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | if ((0 == active_tones_snapshot_length) && (OUTPUT_REACHED_ZERO_BEFORE_OFF == state)) { | ||
229 | state = OUTPUT_OFF; | ||
230 | } | ||
231 | if (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state) { | ||
232 | state = OUTPUT_RUN_NORMALLY; | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | // update audio internal state (note position, current_note, ...) | ||
238 | if (audio_update_state()) { | ||
239 | if (OUTPUT_SHOULD_STOP != state) { | ||
240 | state = OUTPUT_TONES_CHANGED; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | if (OUTPUT_OFF <= state) { | ||
245 | if (OUTPUT_OFF_2 == state) { | ||
246 | // stopping timer6 = stopping the DAC at whatever value it is currently pushing to the output = AUDIO_DAC_OFF_VALUE | ||
247 | gptStopTimer(&GPTD6); | ||
248 | } else { | ||
249 | state++; | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | |||
254 | static void dac_error(DACDriver *dacp, dacerror_t err) { | ||
255 | (void)dacp; | ||
256 | (void)err; | ||
257 | |||
258 | chSysHalt("DAC failure. halp"); | ||
259 | } | ||
260 | |||
261 | static const GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE * 3, | ||
262 | .callback = NULL, | ||
263 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
264 | .dier = 0U}; | ||
265 | |||
266 | static const DACConfig dac_conf = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT}; | ||
267 | |||
268 | /** | ||
269 | * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered | ||
270 | * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency | ||
271 | * to be a third of what we expect. | ||
272 | * | ||
273 | * Here are all the values for DAC_TRG (TSEL in the ref manual) | ||
274 | * TIM15_TRGO 0b011 | ||
275 | * TIM2_TRGO 0b100 | ||
276 | * TIM3_TRGO 0b001 | ||
277 | * TIM6_TRGO 0b000 | ||
278 | * TIM7_TRGO 0b010 | ||
279 | * EXTI9 0b110 | ||
280 | * SWTRIG 0b111 | ||
281 | */ | ||
282 | static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)}; | ||
283 | |||
284 | void audio_driver_initialize() { | ||
285 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
286 | palSetLineMode(A4, PAL_MODE_INPUT_ANALOG); | ||
287 | dacStart(&DACD1, &dac_conf); | ||
288 | } | ||
289 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
290 | palSetLineMode(A5, PAL_MODE_INPUT_ANALOG); | ||
291 | dacStart(&DACD2, &dac_conf); | ||
292 | } | ||
293 | |||
294 | /* enable the output buffer, to directly drive external loads with no additional circuitry | ||
295 | * | ||
296 | * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers | ||
297 | * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer | ||
298 | * Note: enabling the output buffer imparts an additional dc-offset of a couple mV | ||
299 | * | ||
300 | * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet | ||
301 | * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.' | ||
302 | */ | ||
303 | DACD1.params->dac->CR &= ~DAC_CR_BOFF1; | ||
304 | DACD2.params->dac->CR &= ~DAC_CR_BOFF2; | ||
305 | |||
306 | if (AUDIO_PIN == A4) { | ||
307 | dacStartConversion(&DACD1, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE); | ||
308 | } else if (AUDIO_PIN == A5) { | ||
309 | dacStartConversion(&DACD2, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE); | ||
310 | } | ||
311 | |||
312 | // no inverted/out-of-phase waveform (yet?), only pulling AUDIO_PIN_ALT to AUDIO_DAC_OFF_VALUE | ||
313 | #if defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
314 | if (AUDIO_PIN_ALT == A4) { | ||
315 | dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE); | ||
316 | } else if (AUDIO_PIN_ALT == A5) { | ||
317 | dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE); | ||
318 | } | ||
319 | #endif | ||
320 | |||
321 | gptStart(&GPTD6, &gpt6cfg1); | ||
322 | } | ||
323 | |||
324 | void audio_driver_stop(void) { state = OUTPUT_SHOULD_STOP; } | ||
325 | |||
326 | void audio_driver_start(void) { | ||
327 | gptStartContinuous(&GPTD6, 2U); | ||
328 | |||
329 | for (uint8_t i = 0; i < AUDIO_MAX_SIMULTANEOUS_TONES; i++) { | ||
330 | dac_if[i] = 0.0f; | ||
331 | active_tones_snapshot[i] = 0.0f; | ||
332 | } | ||
333 | active_tones_snapshot_length = 0; | ||
334 | state = OUTPUT_SHOULD_START; | ||
335 | } | ||
diff --git a/platforms/chibios/drivers/audio_dac_basic.c b/platforms/chibios/drivers/audio_dac_basic.c new file mode 100644 index 000000000..fac651350 --- /dev/null +++ b/platforms/chibios/drivers/audio_dac_basic.c | |||
@@ -0,0 +1,245 @@ | |||
1 | /* Copyright 2016-2020 Jack Humbert | ||
2 | * Copyright 2020 JohSchneider | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "audio.h" | ||
19 | #include "ch.h" | ||
20 | #include "hal.h" | ||
21 | |||
22 | /* | ||
23 | Audio Driver: DAC | ||
24 | |||
25 | which utilizes both channels of the DAC unit many STM32 are equipped with to output a modulated square-wave, from precomputed samples stored in a buffer, which is passed to the hardware through DMA | ||
26 | |||
27 | this driver can either be used to drive to separate speakers, wired to A4+Gnd and A5+Gnd, which allows two tones to be played simultaneously | ||
28 | OR | ||
29 | one speaker wired to A4+A5 with the AUDIO_PIN_ALT_AS_NEGATIVE define set - see docs/feature_audio | ||
30 | |||
31 | */ | ||
32 | |||
33 | #if !defined(AUDIO_PIN) | ||
34 | # pragma message "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC basic)' for available options." | ||
35 | // TODO: make this an 'error' instead; go through a breaking change, and add AUDIO_PIN A5 to all keyboards currently using AUDIO on STM32 based boards? - for now: set the define here | ||
36 | # define AUDIO_PIN A5 | ||
37 | #endif | ||
38 | // check configuration for ONE speaker, connected to both DAC pins | ||
39 | #if defined(AUDIO_PIN_ALT_AS_NEGATIVE) && !defined(AUDIO_PIN_ALT) | ||
40 | # error "Audio feature: AUDIO_PIN_ALT_AS_NEGATIVE set, but no pin configured as AUDIO_PIN_ALT" | ||
41 | #endif | ||
42 | |||
43 | #ifndef AUDIO_PIN_ALT | ||
44 | // no ALT pin defined is valid, but the c-ifs below need some value set | ||
45 | # define AUDIO_PIN_ALT -1 | ||
46 | #endif | ||
47 | |||
48 | #if !defined(AUDIO_STATE_TIMER) | ||
49 | # define AUDIO_STATE_TIMER GPTD8 | ||
50 | #endif | ||
51 | |||
52 | // square-wave | ||
53 | static const dacsample_t dac_buffer_1[AUDIO_DAC_BUFFER_SIZE] = { | ||
54 | // First half is max, second half is 0 | ||
55 | [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = AUDIO_DAC_SAMPLE_MAX, | ||
56 | [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = 0, | ||
57 | }; | ||
58 | |||
59 | // square-wave | ||
60 | static const dacsample_t dac_buffer_2[AUDIO_DAC_BUFFER_SIZE] = { | ||
61 | // opposite of dac_buffer above | ||
62 | [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, | ||
63 | [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, | ||
64 | }; | ||
65 | |||
66 | GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE, | ||
67 | .callback = NULL, | ||
68 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
69 | .dier = 0U}; | ||
70 | GPTConfig gpt7cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE, | ||
71 | .callback = NULL, | ||
72 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
73 | .dier = 0U}; | ||
74 | |||
75 | static void gpt_audio_state_cb(GPTDriver *gptp); | ||
76 | GPTConfig gptStateUpdateCfg = {.frequency = 10, | ||
77 | .callback = gpt_audio_state_cb, | ||
78 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
79 | .dier = 0U}; | ||
80 | |||
81 | static const DACConfig dac_conf_ch1 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT}; | ||
82 | static const DACConfig dac_conf_ch2 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT}; | ||
83 | |||
84 | /** | ||
85 | * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered | ||
86 | * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency | ||
87 | * to be a third of what we expect. | ||
88 | * | ||
89 | * Here are all the values for DAC_TRG (TSEL in the ref manual) | ||
90 | * TIM15_TRGO 0b011 | ||
91 | * TIM2_TRGO 0b100 | ||
92 | * TIM3_TRGO 0b001 | ||
93 | * TIM6_TRGO 0b000 | ||
94 | * TIM7_TRGO 0b010 | ||
95 | * EXTI9 0b110 | ||
96 | * SWTRIG 0b111 | ||
97 | */ | ||
98 | static const DACConversionGroup dac_conv_grp_ch1 = {.num_channels = 1U, .trigger = DAC_TRG(0b000)}; | ||
99 | static const DACConversionGroup dac_conv_grp_ch2 = {.num_channels = 1U, .trigger = DAC_TRG(0b010)}; | ||
100 | |||
101 | void channel_1_start(void) { | ||
102 | gptStart(&GPTD6, &gpt6cfg1); | ||
103 | gptStartContinuous(&GPTD6, 2U); | ||
104 | palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); | ||
105 | } | ||
106 | |||
107 | void channel_1_stop(void) { | ||
108 | gptStopTimer(&GPTD6); | ||
109 | palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL); | ||
110 | palSetPad(GPIOA, 4); | ||
111 | } | ||
112 | |||
113 | static float channel_1_frequency = 0.0f; | ||
114 | void channel_1_set_frequency(float freq) { | ||
115 | channel_1_frequency = freq; | ||
116 | |||
117 | channel_1_stop(); | ||
118 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
119 | return; | ||
120 | |||
121 | gpt6cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE; | ||
122 | channel_1_start(); | ||
123 | } | ||
124 | float channel_1_get_frequency(void) { return channel_1_frequency; } | ||
125 | |||
126 | void channel_2_start(void) { | ||
127 | gptStart(&GPTD7, &gpt7cfg1); | ||
128 | gptStartContinuous(&GPTD7, 2U); | ||
129 | palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); | ||
130 | } | ||
131 | |||
132 | void channel_2_stop(void) { | ||
133 | gptStopTimer(&GPTD7); | ||
134 | palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL); | ||
135 | palSetPad(GPIOA, 5); | ||
136 | } | ||
137 | |||
138 | static float channel_2_frequency = 0.0f; | ||
139 | void channel_2_set_frequency(float freq) { | ||
140 | channel_2_frequency = freq; | ||
141 | |||
142 | channel_2_stop(); | ||
143 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
144 | return; | ||
145 | |||
146 | gpt7cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE; | ||
147 | channel_2_start(); | ||
148 | } | ||
149 | float channel_2_get_frequency(void) { return channel_2_frequency; } | ||
150 | |||
151 | static void gpt_audio_state_cb(GPTDriver *gptp) { | ||
152 | if (audio_update_state()) { | ||
153 | #if defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
154 | // one piezo/speaker connected to both audio pins, the generated square-waves are inverted | ||
155 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
156 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
157 | |||
158 | #else // two separate audio outputs/speakers | ||
159 | // primary speaker on A4, optional secondary on A5 | ||
160 | if (AUDIO_PIN == A4) { | ||
161 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
162 | if (AUDIO_PIN_ALT == A5) { | ||
163 | if (audio_get_number_of_active_tones() > 1) { | ||
164 | channel_2_set_frequency(audio_get_processed_frequency(1)); | ||
165 | } else { | ||
166 | channel_2_stop(); | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | // primary speaker on A5, optional secondary on A4 | ||
172 | if (AUDIO_PIN == A5) { | ||
173 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
174 | if (AUDIO_PIN_ALT == A4) { | ||
175 | if (audio_get_number_of_active_tones() > 1) { | ||
176 | channel_1_set_frequency(audio_get_processed_frequency(1)); | ||
177 | } else { | ||
178 | channel_1_stop(); | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | #endif | ||
183 | } | ||
184 | } | ||
185 | |||
186 | void audio_driver_initialize() { | ||
187 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
188 | palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); | ||
189 | dacStart(&DACD1, &dac_conf_ch1); | ||
190 | |||
191 | // initial setup of the dac-triggering timer is still required, even | ||
192 | // though it gets reconfigured and restarted later on | ||
193 | gptStart(&GPTD6, &gpt6cfg1); | ||
194 | } | ||
195 | |||
196 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
197 | palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); | ||
198 | dacStart(&DACD2, &dac_conf_ch2); | ||
199 | |||
200 | gptStart(&GPTD7, &gpt7cfg1); | ||
201 | } | ||
202 | |||
203 | /* enable the output buffer, to directly drive external loads with no additional circuitry | ||
204 | * | ||
205 | * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers | ||
206 | * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer | ||
207 | * Note: enabling the output buffer imparts an additional dc-offset of a couple mV | ||
208 | * | ||
209 | * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet | ||
210 | * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.' | ||
211 | */ | ||
212 | DACD1.params->dac->CR &= ~DAC_CR_BOFF1; | ||
213 | DACD2.params->dac->CR &= ~DAC_CR_BOFF2; | ||
214 | |||
215 | // start state-updater | ||
216 | gptStart(&AUDIO_STATE_TIMER, &gptStateUpdateCfg); | ||
217 | } | ||
218 | |||
219 | void audio_driver_stop(void) { | ||
220 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
221 | gptStopTimer(&GPTD6); | ||
222 | |||
223 | // stop the ongoing conversion and put the output in a known state | ||
224 | dacStopConversion(&DACD1); | ||
225 | dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE); | ||
226 | } | ||
227 | |||
228 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
229 | gptStopTimer(&GPTD7); | ||
230 | |||
231 | dacStopConversion(&DACD2); | ||
232 | dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE); | ||
233 | } | ||
234 | gptStopTimer(&AUDIO_STATE_TIMER); | ||
235 | } | ||
236 | |||
237 | void audio_driver_start(void) { | ||
238 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
239 | dacStartConversion(&DACD1, &dac_conv_grp_ch1, (dacsample_t *)dac_buffer_1, AUDIO_DAC_BUFFER_SIZE); | ||
240 | } | ||
241 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
242 | dacStartConversion(&DACD2, &dac_conv_grp_ch2, (dacsample_t *)dac_buffer_2, AUDIO_DAC_BUFFER_SIZE); | ||
243 | } | ||
244 | gptStartContinuous(&AUDIO_STATE_TIMER, 2U); | ||
245 | } | ||
diff --git a/platforms/chibios/drivers/audio_pwm.h b/platforms/chibios/drivers/audio_pwm.h new file mode 100644 index 000000000..86cab916e --- /dev/null +++ b/platforms/chibios/drivers/audio_pwm.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* Copyright 2020 Jack Humbert | ||
2 | * Copyright 2020 JohSchneider | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | #pragma once | ||
18 | |||
19 | #if !defined(AUDIO_PWM_DRIVER) | ||
20 | // NOTE: Timer2 seems to be used otherwise in QMK, otherwise we could default to A5 (= TIM2_CH1, with PWMD2 and alternate-function(1)) | ||
21 | # define AUDIO_PWM_DRIVER PWMD1 | ||
22 | #endif | ||
23 | |||
24 | #if !defined(AUDIO_PWM_CHANNEL) | ||
25 | // NOTE: sticking to the STM data-sheet numbering: TIMxCH1 to TIMxCH4 | ||
26 | // default: STM32F303CC PA8+TIM1_CH1 -> 1 | ||
27 | # define AUDIO_PWM_CHANNEL 1 | ||
28 | #endif | ||
29 | |||
30 | #if !defined(AUDIO_PWM_PAL_MODE) | ||
31 | // pin-alternate function: see the data-sheet for which pin needs what AF to connect to TIMx_CHy | ||
32 | // default: STM32F303CC PA8+TIM1_CH1 -> 6 | ||
33 | # define AUDIO_PWM_PAL_MODE 6 | ||
34 | #endif | ||
35 | |||
36 | #if !defined(AUDIO_STATE_TIMER) | ||
37 | // timer used to trigger updates in the audio-system, configured/enabled in chibios mcuconf. | ||
38 | // Tim6 is the default for "larger" STMs, smaller ones might not have this one (enabled) and need to switch to a different one (e.g.: STM32F103 has only Tim1-Tim4) | ||
39 | # define AUDIO_STATE_TIMER GPTD6 | ||
40 | #endif | ||
diff --git a/platforms/chibios/drivers/audio_pwm_hardware.c b/platforms/chibios/drivers/audio_pwm_hardware.c new file mode 100644 index 000000000..cd40019ee --- /dev/null +++ b/platforms/chibios/drivers/audio_pwm_hardware.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* Copyright 2020 Jack Humbert | ||
2 | * Copyright 2020 JohSchneider | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | Audio Driver: PWM | ||
20 | |||
21 | the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back. | ||
22 | |||
23 | this driver uses the chibios-PWM system to produce a square-wave on specific output pins that are connected to the PWM hardware. | ||
24 | The hardware directly toggles the pin via its alternate function. see your MCUs data-sheet for which pin can be driven by what timer - looking for TIMx_CHy and the corresponding alternate function. | ||
25 | |||
26 | */ | ||
27 | |||
28 | #include "audio.h" | ||
29 | #include "ch.h" | ||
30 | #include "hal.h" | ||
31 | |||
32 | #if !defined(AUDIO_PIN) | ||
33 | # error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings" | ||
34 | #endif | ||
35 | |||
36 | extern bool playing_note; | ||
37 | extern bool playing_melody; | ||
38 | extern uint8_t note_timbre; | ||
39 | |||
40 | static PWMConfig pwmCFG = { | ||
41 | .frequency = 100000, /* PWM clock frequency */ | ||
42 | // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime | ||
43 | .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */ | ||
44 | .callback = NULL, /* no callback, the hardware directly toggles the pin */ | ||
45 | .channels = | ||
46 | { | ||
47 | #if AUDIO_PWM_CHANNEL == 4 | ||
48 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 0 -> TIMx_CH1 */ | ||
49 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */ | ||
50 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */ | ||
51 | {PWM_OUTPUT_ACTIVE_HIGH, NULL} /* channel 3 -> TIMx_CH4 */ | ||
52 | #elif AUDIO_PWM_CHANNEL == 3 | ||
53 | {PWM_OUTPUT_DISABLED, NULL}, | ||
54 | {PWM_OUTPUT_DISABLED, NULL}, | ||
55 | {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH3 */ | ||
56 | {PWM_OUTPUT_DISABLED, NULL} | ||
57 | #elif AUDIO_PWM_CHANNEL == 2 | ||
58 | {PWM_OUTPUT_DISABLED, NULL}, | ||
59 | {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH2 */ | ||
60 | {PWM_OUTPUT_DISABLED, NULL}, | ||
61 | {PWM_OUTPUT_DISABLED, NULL} | ||
62 | #else /*fallback to CH1 */ | ||
63 | {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH1 */ | ||
64 | {PWM_OUTPUT_DISABLED, NULL}, | ||
65 | {PWM_OUTPUT_DISABLED, NULL}, | ||
66 | {PWM_OUTPUT_DISABLED, NULL} | ||
67 | #endif | ||
68 | }, | ||
69 | }; | ||
70 | |||
71 | static float channel_1_frequency = 0.0f; | ||
72 | void channel_1_set_frequency(float freq) { | ||
73 | channel_1_frequency = freq; | ||
74 | |||
75 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
76 | return; | ||
77 | |||
78 | pwmcnt_t period = (pwmCFG.frequency / freq); | ||
79 | pwmChangePeriod(&AUDIO_PWM_DRIVER, period); | ||
80 | pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, | ||
81 | // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH | ||
82 | PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100)); | ||
83 | } | ||
84 | |||
85 | float channel_1_get_frequency(void) { return channel_1_frequency; } | ||
86 | |||
87 | void channel_1_start(void) { | ||
88 | pwmStop(&AUDIO_PWM_DRIVER); | ||
89 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
90 | } | ||
91 | |||
92 | void channel_1_stop(void) { pwmStop(&AUDIO_PWM_DRIVER); } | ||
93 | |||
94 | static void gpt_callback(GPTDriver *gptp); | ||
95 | GPTConfig gptCFG = { | ||
96 | /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64 | ||
97 | the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4 | ||
98 | the tempo (which might vary!) is in bpm (beats per minute) | ||
99 | therefore: if the timer ticks away at .frequency = (60*64)Hz, | ||
100 | and the .interval counts from 64 downwards - audio_update_state is | ||
101 | called just often enough to not miss any notes | ||
102 | */ | ||
103 | .frequency = 60 * 64, | ||
104 | .callback = gpt_callback, | ||
105 | }; | ||
106 | |||
107 | void audio_driver_initialize(void) { | ||
108 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
109 | |||
110 | // connect the AUDIO_PIN to the PWM hardware | ||
111 | #if defined(USE_GPIOV1) // STM32F103C8 | ||
112 | palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE_PUSHPULL); | ||
113 | #else // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command) | ||
114 | palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE(AUDIO_PWM_PAL_MODE)); | ||
115 | #endif | ||
116 | |||
117 | gptStart(&AUDIO_STATE_TIMER, &gptCFG); | ||
118 | } | ||
119 | |||
120 | void audio_driver_start(void) { | ||
121 | channel_1_stop(); | ||
122 | channel_1_start(); | ||
123 | |||
124 | if (playing_note || playing_melody) { | ||
125 | gptStartContinuous(&AUDIO_STATE_TIMER, 64); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | void audio_driver_stop(void) { | ||
130 | channel_1_stop(); | ||
131 | gptStopTimer(&AUDIO_STATE_TIMER); | ||
132 | } | ||
133 | |||
134 | /* a regular timer task, that checks the note to be currently played | ||
135 | * and updates the pwm to output that frequency | ||
136 | */ | ||
137 | static void gpt_callback(GPTDriver *gptp) { | ||
138 | float freq; // TODO: freq_alt | ||
139 | |||
140 | if (audio_update_state()) { | ||
141 | freq = audio_get_processed_frequency(0); // freq_alt would be index=1 | ||
142 | channel_1_set_frequency(freq); | ||
143 | } | ||
144 | } | ||
diff --git a/platforms/chibios/drivers/audio_pwm_software.c b/platforms/chibios/drivers/audio_pwm_software.c new file mode 100644 index 000000000..15c3e98b6 --- /dev/null +++ b/platforms/chibios/drivers/audio_pwm_software.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* Copyright 2020 Jack Humbert | ||
2 | * Copyright 2020 JohSchneider | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | Audio Driver: PWM | ||
20 | |||
21 | the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back. | ||
22 | |||
23 | this driver uses the chibios-PWM system to produce a square-wave on any given output pin in software | ||
24 | - a pwm callback is used to set/clear the configured pin. | ||
25 | |||
26 | */ | ||
27 | #include "audio.h" | ||
28 | #include "ch.h" | ||
29 | #include "hal.h" | ||
30 | |||
31 | #if !defined(AUDIO_PIN) | ||
32 | # error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings" | ||
33 | #endif | ||
34 | extern bool playing_note; | ||
35 | extern bool playing_melody; | ||
36 | extern uint8_t note_timbre; | ||
37 | |||
38 | static void pwm_audio_period_callback(PWMDriver *pwmp); | ||
39 | static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp); | ||
40 | |||
41 | static PWMConfig pwmCFG = { | ||
42 | .frequency = 100000, /* PWM clock frequency */ | ||
43 | // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime | ||
44 | .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */ | ||
45 | .callback = pwm_audio_period_callback, | ||
46 | .channels = | ||
47 | { | ||
48 | // software-PWM just needs another callback on any channel | ||
49 | {PWM_OUTPUT_ACTIVE_HIGH, pwm_audio_channel_interrupt_callback}, /* channel 0 -> TIMx_CH1 */ | ||
50 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */ | ||
51 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */ | ||
52 | {PWM_OUTPUT_DISABLED, NULL} /* channel 3 -> TIMx_CH4 */ | ||
53 | }, | ||
54 | }; | ||
55 | |||
56 | static float channel_1_frequency = 0.0f; | ||
57 | void channel_1_set_frequency(float freq) { | ||
58 | channel_1_frequency = freq; | ||
59 | |||
60 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
61 | return; | ||
62 | |||
63 | pwmcnt_t period = (pwmCFG.frequency / freq); | ||
64 | pwmChangePeriod(&AUDIO_PWM_DRIVER, period); | ||
65 | |||
66 | pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, | ||
67 | // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH | ||
68 | PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100)); | ||
69 | } | ||
70 | |||
71 | float channel_1_get_frequency(void) { return channel_1_frequency; } | ||
72 | |||
73 | void channel_1_start(void) { | ||
74 | pwmStop(&AUDIO_PWM_DRIVER); | ||
75 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
76 | |||
77 | pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); | ||
78 | pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1); | ||
79 | } | ||
80 | |||
81 | void channel_1_stop(void) { | ||
82 | pwmStop(&AUDIO_PWM_DRIVER); | ||
83 | |||
84 | palClearLine(AUDIO_PIN); // leave the line low, after last note was played | ||
85 | |||
86 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
87 | palClearLine(AUDIO_PIN_ALT); // leave the line low, after last note was played | ||
88 | #endif | ||
89 | } | ||
90 | |||
91 | // generate a PWM signal on any pin, not necessarily the one connected to the timer | ||
92 | static void pwm_audio_period_callback(PWMDriver *pwmp) { | ||
93 | (void)pwmp; | ||
94 | palClearLine(AUDIO_PIN); | ||
95 | |||
96 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
97 | palSetLine(AUDIO_PIN_ALT); | ||
98 | #endif | ||
99 | } | ||
100 | static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp) { | ||
101 | (void)pwmp; | ||
102 | if (channel_1_frequency > 0) { | ||
103 | palSetLine(AUDIO_PIN); // generate a PWM signal on any pin, not necessarily the one connected to the timer | ||
104 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
105 | palClearLine(AUDIO_PIN_ALT); | ||
106 | #endif | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static void gpt_callback(GPTDriver *gptp); | ||
111 | GPTConfig gptCFG = { | ||
112 | /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64 | ||
113 | the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4 | ||
114 | the tempo (which might vary!) is in bpm (beats per minute) | ||
115 | therefore: if the timer ticks away at .frequency = (60*64)Hz, | ||
116 | and the .interval counts from 64 downwards - audio_update_state is | ||
117 | called just often enough to not miss anything | ||
118 | */ | ||
119 | .frequency = 60 * 64, | ||
120 | .callback = gpt_callback, | ||
121 | }; | ||
122 | |||
123 | void audio_driver_initialize(void) { | ||
124 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
125 | |||
126 | palSetLineMode(AUDIO_PIN, PAL_MODE_OUTPUT_PUSHPULL); | ||
127 | palClearLine(AUDIO_PIN); | ||
128 | |||
129 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
130 | palSetLineMode(AUDIO_PIN_ALT, PAL_MODE_OUTPUT_PUSHPULL); | ||
131 | palClearLine(AUDIO_PIN_ALT); | ||
132 | #endif | ||
133 | |||
134 | pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); // enable pwm callbacks | ||
135 | pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1); | ||
136 | |||
137 | gptStart(&AUDIO_STATE_TIMER, &gptCFG); | ||
138 | } | ||
139 | |||
140 | void audio_driver_start(void) { | ||
141 | channel_1_stop(); | ||
142 | channel_1_start(); | ||
143 | |||
144 | if (playing_note || playing_melody) { | ||
145 | gptStartContinuous(&AUDIO_STATE_TIMER, 64); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | void audio_driver_stop(void) { | ||
150 | channel_1_stop(); | ||
151 | gptStopTimer(&AUDIO_STATE_TIMER); | ||
152 | } | ||
153 | |||
154 | /* a regular timer task, that checks the note to be currently played | ||
155 | * and updates the pwm to output that frequency | ||
156 | */ | ||
157 | static void gpt_callback(GPTDriver *gptp) { | ||
158 | float freq; // TODO: freq_alt | ||
159 | |||
160 | if (audio_update_state()) { | ||
161 | freq = audio_get_processed_frequency(0); // freq_alt would be index=1 | ||
162 | channel_1_set_frequency(freq); | ||
163 | } | ||
164 | } | ||
diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index fc4bb2ab3..63e85ae87 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c | |||
@@ -63,16 +63,16 @@ __attribute__((weak)) void i2c_init(void) { | |||
63 | is_initialised = true; | 63 | is_initialised = true; |
64 | 64 | ||
65 | // Try releasing special pins for a short time | 65 | // Try releasing special pins for a short time |
66 | palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_INPUT); | 66 | palSetLineMode(I2C1_SCL_PIN, PAL_MODE_INPUT); |
67 | palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_INPUT); | 67 | palSetLineMode(I2C1_SDA_PIN, PAL_MODE_INPUT); |
68 | 68 | ||
69 | chThdSleepMilliseconds(10); | 69 | chThdSleepMilliseconds(10); |
70 | #if defined(USE_GPIOV1) | 70 | #if defined(USE_GPIOV1) |
71 | palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, I2C1_SCL_PAL_MODE); | 71 | palSetLineMode(I2C1_SCL_PIN, I2C1_SCL_PAL_MODE); |
72 | palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, I2C1_SDA_PAL_MODE); | 72 | palSetLineMode(I2C1_SDA_PIN, I2C1_SDA_PAL_MODE); |
73 | #else | 73 | #else |
74 | palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); | 74 | palSetLineMode(I2C1_SCL_PIN, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN); |
75 | palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); | 75 | palSetLineMode(I2C1_SDA_PIN, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN); |
76 | #endif | 76 | #endif |
77 | } | 77 | } |
78 | } | 78 | } |
@@ -102,7 +102,7 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, | |||
102 | i2cStart(&I2C_DRIVER, &i2cconfig); | 102 | i2cStart(&I2C_DRIVER, &i2cconfig); |
103 | 103 | ||
104 | uint8_t complete_packet[length + 1]; | 104 | uint8_t complete_packet[length + 1]; |
105 | for (uint8_t i = 0; i < length; i++) { | 105 | for (uint16_t i = 0; i < length; i++) { |
106 | complete_packet[i + 1] = data[i]; | 106 | complete_packet[i + 1] = data[i]; |
107 | } | 107 | } |
108 | complete_packet[0] = regaddr; | 108 | complete_packet[0] = regaddr; |
@@ -111,6 +111,21 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, | |||
111 | return chibios_to_qmk(&status); | 111 | return chibios_to_qmk(&status); |
112 | } | 112 | } |
113 | 113 | ||
114 | i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { | ||
115 | i2c_address = devaddr; | ||
116 | i2cStart(&I2C_DRIVER, &i2cconfig); | ||
117 | |||
118 | uint8_t complete_packet[length + 2]; | ||
119 | for (uint16_t i = 0; i < length; i++) { | ||
120 | complete_packet[i + 2] = data[i]; | ||
121 | } | ||
122 | complete_packet[0] = regaddr >> 8; | ||
123 | complete_packet[1] = regaddr & 0xFF; | ||
124 | |||
125 | msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 2, 0, 0, TIME_MS2I(timeout)); | ||
126 | return chibios_to_qmk(&status); | ||
127 | } | ||
128 | |||
114 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { | 129 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { |
115 | i2c_address = devaddr; | 130 | i2c_address = devaddr; |
116 | i2cStart(&I2C_DRIVER, &i2cconfig); | 131 | i2cStart(&I2C_DRIVER, &i2cconfig); |
@@ -118,4 +133,12 @@ i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16 | |||
118 | return chibios_to_qmk(&status); | 133 | return chibios_to_qmk(&status); |
119 | } | 134 | } |
120 | 135 | ||
136 | i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { | ||
137 | i2c_address = devaddr; | ||
138 | i2cStart(&I2C_DRIVER, &i2cconfig); | ||
139 | uint8_t register_packet[2] = {regaddr >> 8, regaddr & 0xFF}; | ||
140 | msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), register_packet, 2, data, length, TIME_MS2I(timeout)); | ||
141 | return chibios_to_qmk(&status); | ||
142 | } | ||
143 | |||
121 | void i2c_stop(void) { i2cStop(&I2C_DRIVER); } | 144 | void i2c_stop(void) { i2cStop(&I2C_DRIVER); } |
diff --git a/platforms/chibios/drivers/i2c_master.h b/platforms/chibios/drivers/i2c_master.h index c68109acb..5f082e9d1 100644 --- a/platforms/chibios/drivers/i2c_master.h +++ b/platforms/chibios/drivers/i2c_master.h | |||
@@ -27,24 +27,11 @@ | |||
27 | #include <ch.h> | 27 | #include <ch.h> |
28 | #include <hal.h> | 28 | #include <hal.h> |
29 | 29 | ||
30 | #ifdef I2C1_BANK | 30 | #ifndef I2C1_SCL_PIN |
31 | # define I2C1_SCL_BANK I2C1_BANK | 31 | # define I2C1_SCL_PIN B6 |
32 | # define I2C1_SDA_BANK I2C1_BANK | ||
33 | #endif | 32 | #endif |
34 | 33 | #ifndef I2C1_SDA_PIN | |
35 | #ifndef I2C1_SCL_BANK | 34 | # define I2C1_SDA_PIN B7 |
36 | # define I2C1_SCL_BANK GPIOB | ||
37 | #endif | ||
38 | |||
39 | #ifndef I2C1_SDA_BANK | ||
40 | # define I2C1_SDA_BANK GPIOB | ||
41 | #endif | ||
42 | |||
43 | #ifndef I2C1_SCL | ||
44 | # define I2C1_SCL 6 | ||
45 | #endif | ||
46 | #ifndef I2C1_SDA | ||
47 | # define I2C1_SDA 7 | ||
48 | #endif | 35 | #endif |
49 | 36 | ||
50 | #ifdef USE_I2CV1 | 37 | #ifdef USE_I2CV1 |
@@ -83,10 +70,10 @@ | |||
83 | 70 | ||
84 | #ifdef USE_GPIOV1 | 71 | #ifdef USE_GPIOV1 |
85 | # ifndef I2C1_SCL_PAL_MODE | 72 | # ifndef I2C1_SCL_PAL_MODE |
86 | # define I2C1_SCL_PAL_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN | 73 | # define I2C1_SCL_PAL_MODE PAL_MODE_ALTERNATE_OPENDRAIN |
87 | # endif | 74 | # endif |
88 | # ifndef I2C1_SDA_PAL_MODE | 75 | # ifndef I2C1_SDA_PAL_MODE |
89 | # define I2C1_SDA_PAL_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN | 76 | # define I2C1_SDA_PAL_MODE PAL_MODE_ALTERNATE_OPENDRAIN |
90 | # endif | 77 | # endif |
91 | #else | 78 | #else |
92 | // The default PAL alternate modes are used to signal that the pins are used for I2C | 79 | // The default PAL alternate modes are used to signal that the pins are used for I2C |
@@ -109,5 +96,7 @@ i2c_status_t i2c_start(uint8_t address); | |||
109 | i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); | 96 | i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); |
110 | i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); | 97 | i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); |
111 | i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); | 98 | i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); |
99 | i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); | ||
112 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); | 100 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); |
101 | i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); | ||
113 | void i2c_stop(void); | 102 | void i2c_stop(void); |
diff --git a/platforms/chibios/drivers/ps2/ps2_io.c b/platforms/chibios/drivers/ps2/ps2_io.c new file mode 100644 index 000000000..906d85d84 --- /dev/null +++ b/platforms/chibios/drivers/ps2/ps2_io.c | |||
@@ -0,0 +1,55 @@ | |||
1 | #include <stdbool.h> | ||
2 | #include "ps2_io.h" | ||
3 | |||
4 | // chibiOS headers | ||
5 | #include "ch.h" | ||
6 | #include "hal.h" | ||
7 | |||
8 | /* Check port settings for clock and data line */ | ||
9 | #if !(defined(PS2_CLOCK_PIN)) | ||
10 | # error "PS/2 clock setting is required in config.h" | ||
11 | #endif | ||
12 | |||
13 | #if !(defined(PS2_DATA_PIN)) | ||
14 | # error "PS/2 data setting is required in config.h" | ||
15 | #endif | ||
16 | |||
17 | /* | ||
18 | * Clock | ||
19 | */ | ||
20 | void clock_init(void) {} | ||
21 | |||
22 | void clock_lo(void) { | ||
23 | palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_OUTPUT_OPENDRAIN); | ||
24 | palWriteLine(PS2_CLOCK_PIN, PAL_LOW); | ||
25 | } | ||
26 | |||
27 | void clock_hi(void) { | ||
28 | palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_OUTPUT_OPENDRAIN); | ||
29 | palWriteLine(PS2_CLOCK_PIN, PAL_HIGH); | ||
30 | } | ||
31 | |||
32 | bool clock_in(void) { | ||
33 | palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_INPUT); | ||
34 | return palReadLine(PS2_CLOCK_PIN); | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * Data | ||
39 | */ | ||
40 | void data_init(void) {} | ||
41 | |||
42 | void data_lo(void) { | ||
43 | palSetLineMode(PS2_DATA_PIN, PAL_MODE_OUTPUT_OPENDRAIN); | ||
44 | palWriteLine(PS2_DATA_PIN, PAL_LOW); | ||
45 | } | ||
46 | |||
47 | void data_hi(void) { | ||
48 | palSetLineMode(PS2_DATA_PIN, PAL_MODE_OUTPUT_OPENDRAIN); | ||
49 | palWriteLine(PS2_DATA_PIN, PAL_HIGH); | ||
50 | } | ||
51 | |||
52 | bool data_in(void) { | ||
53 | palSetLineMode(PS2_DATA_PIN, PAL_MODE_INPUT); | ||
54 | return palReadLine(PS2_DATA_PIN); | ||
55 | } | ||
diff --git a/platforms/chibios/drivers/serial.c b/platforms/chibios/drivers/serial.c index f54fbcee4..ef6f0aa8d 100644 --- a/platforms/chibios/drivers/serial.c +++ b/platforms/chibios/drivers/serial.c | |||
@@ -19,7 +19,7 @@ | |||
19 | # error "chSysPolledDelayX method not supported on this platform" | 19 | # error "chSysPolledDelayX method not supported on this platform" |
20 | #else | 20 | #else |
21 | # undef wait_us | 21 | # undef wait_us |
22 | # define wait_us(x) chSysPolledDelayX(US2RTC(STM32_SYSCLK, x)) | 22 | # define wait_us(x) chSysPolledDelayX(US2RTC(CPU_CLOCK, x)) |
23 | #endif | 23 | #endif |
24 | 24 | ||
25 | #ifndef SELECT_SOFT_SERIAL_SPEED | 25 | #ifndef SELECT_SOFT_SERIAL_SPEED |
diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c index ea4473791..124e4be68 100644 --- a/platforms/chibios/drivers/serial_usart.c +++ b/platforms/chibios/drivers/serial_usart.c | |||
@@ -104,9 +104,9 @@ static inline bool receive(uint8_t* destination, const size_t size) { | |||
104 | __attribute__((weak)) void usart_init(void) { | 104 | __attribute__((weak)) void usart_init(void) { |
105 | # if defined(MCU_STM32) | 105 | # if defined(MCU_STM32) |
106 | # if defined(USE_GPIOV1) | 106 | # if defined(USE_GPIOV1) |
107 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); | 107 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN); |
108 | # else | 108 | # else |
109 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); | 109 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN); |
110 | # endif | 110 | # endif |
111 | 111 | ||
112 | # if defined(USART_REMAP) | 112 | # if defined(USART_REMAP) |
@@ -125,11 +125,11 @@ __attribute__((weak)) void usart_init(void) { | |||
125 | __attribute__((weak)) void usart_init(void) { | 125 | __attribute__((weak)) void usart_init(void) { |
126 | # if defined(MCU_STM32) | 126 | # if defined(MCU_STM32) |
127 | # if defined(USE_GPIOV1) | 127 | # if defined(USE_GPIOV1) |
128 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL); | 128 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL); |
129 | palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT); | 129 | palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT); |
130 | # else | 130 | # else |
131 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); | 131 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); |
132 | palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_RX_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); | 132 | palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_RX_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); |
133 | # endif | 133 | # endif |
134 | 134 | ||
135 | # if defined(USART_REMAP) | 135 | # if defined(USART_REMAP) |
diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c index 28ddcbb2b..c592369dd 100644 --- a/platforms/chibios/drivers/spi_master.c +++ b/platforms/chibios/drivers/spi_master.c | |||
@@ -42,9 +42,9 @@ __attribute__((weak)) void spi_init(void) { | |||
42 | palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE); | 42 | palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE); |
43 | palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE); | 43 | palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE); |
44 | #else | 44 | #else |
45 | palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); | 45 | palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); |
46 | palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); | 46 | palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); |
47 | palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); | 47 | palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); |
48 | #endif | 48 | #endif |
49 | } | 49 | } |
50 | } | 50 | } |
@@ -110,6 +110,31 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) { | |||
110 | spiConfig.tar0 |= SPIx_CTARn_BR(8); | 110 | spiConfig.tar0 |= SPIx_CTARn_BR(8); |
111 | break; | 111 | break; |
112 | } | 112 | } |
113 | |||
114 | #elif defined(HT32) | ||
115 | spiConfig.cr0 = SPI_CR0_SELOEN; | ||
116 | spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode | ||
117 | |||
118 | if (lsbFirst) { | ||
119 | spiConfig.cr1 |= SPI_CR1_FIRSTBIT; | ||
120 | } | ||
121 | |||
122 | switch (mode) { | ||
123 | case 0: | ||
124 | spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0; | ||
125 | break; | ||
126 | case 1: | ||
127 | spiConfig.cr1 |= SPI_CR1_FORMAT_MODE1; | ||
128 | break; | ||
129 | case 2: | ||
130 | spiConfig.cr1 |= SPI_CR1_FORMAT_MODE2; | ||
131 | break; | ||
132 | case 3: | ||
133 | spiConfig.cr1 |= SPI_CR1_FORMAT_MODE3; | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | spiConfig.cpr = (roundedDivisor - 1) >> 1; | ||
113 | #else | 138 | #else |
114 | spiConfig.cr1 = 0; | 139 | spiConfig.cr1 = 0; |
115 | 140 | ||
diff --git a/platforms/chibios/drivers/spi_master.h b/platforms/chibios/drivers/spi_master.h index b5a6ef143..6a3ce481f 100644 --- a/platforms/chibios/drivers/spi_master.h +++ b/platforms/chibios/drivers/spi_master.h | |||
@@ -33,7 +33,7 @@ | |||
33 | 33 | ||
34 | #ifndef SPI_SCK_PAL_MODE | 34 | #ifndef SPI_SCK_PAL_MODE |
35 | # if defined(USE_GPIOV1) | 35 | # if defined(USE_GPIOV1) |
36 | # define SPI_SCK_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 36 | # define SPI_SCK_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL |
37 | # else | 37 | # else |
38 | # define SPI_SCK_PAL_MODE 5 | 38 | # define SPI_SCK_PAL_MODE 5 |
39 | # endif | 39 | # endif |
@@ -45,7 +45,7 @@ | |||
45 | 45 | ||
46 | #ifndef SPI_MOSI_PAL_MODE | 46 | #ifndef SPI_MOSI_PAL_MODE |
47 | # if defined(USE_GPIOV1) | 47 | # if defined(USE_GPIOV1) |
48 | # define SPI_MOSI_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 48 | # define SPI_MOSI_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL |
49 | # else | 49 | # else |
50 | # define SPI_MOSI_PAL_MODE 5 | 50 | # define SPI_MOSI_PAL_MODE 5 |
51 | # endif | 51 | # endif |
@@ -57,7 +57,7 @@ | |||
57 | 57 | ||
58 | #ifndef SPI_MISO_PAL_MODE | 58 | #ifndef SPI_MISO_PAL_MODE |
59 | # if defined(USE_GPIOV1) | 59 | # if defined(USE_GPIOV1) |
60 | # define SPI_MISO_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 60 | # define SPI_MISO_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL |
61 | # else | 61 | # else |
62 | # define SPI_MISO_PAL_MODE 5 | 62 | # define SPI_MISO_PAL_MODE 5 |
63 | # endif | 63 | # endif |
diff --git a/platforms/chibios/drivers/uart.c b/platforms/chibios/drivers/uart.c index 030335b34..0e8e0515a 100644 --- a/platforms/chibios/drivers/uart.c +++ b/platforms/chibios/drivers/uart.c | |||
@@ -29,11 +29,11 @@ void uart_init(uint32_t baud) { | |||
29 | serialConfig.speed = baud; | 29 | serialConfig.speed = baud; |
30 | 30 | ||
31 | #if defined(USE_GPIOV1) | 31 | #if defined(USE_GPIOV1) |
32 | palSetLineMode(SD1_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); | 32 | palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN); |
33 | palSetLineMode(SD1_RX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); | 33 | palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN); |
34 | #else | 34 | #else |
35 | palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE(SD1_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); | 35 | palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE(SD1_TX_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN); |
36 | palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE(SD1_RX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); | 36 | palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE(SD1_RX_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN); |
37 | #endif | 37 | #endif |
38 | sdStart(&SERIAL_DRIVER, &serialConfig); | 38 | sdStart(&SERIAL_DRIVER, &serialConfig); |
39 | } | 39 | } |
diff --git a/platforms/chibios/drivers/ws2812.c b/platforms/chibios/drivers/ws2812.c index 0d12e2fb7..b46c46ae5 100644 --- a/platforms/chibios/drivers/ws2812.c +++ b/platforms/chibios/drivers/ws2812.c | |||
@@ -6,7 +6,7 @@ | |||
6 | /* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */ | 6 | /* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */ |
7 | 7 | ||
8 | #ifndef NOP_FUDGE | 8 | #ifndef NOP_FUDGE |
9 | # if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) | 9 | # if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) |
10 | # define NOP_FUDGE 0.4 | 10 | # define NOP_FUDGE 0.4 |
11 | # else | 11 | # else |
12 | # error("NOP_FUDGE configuration required") | 12 | # error("NOP_FUDGE configuration required") |
@@ -23,7 +23,7 @@ | |||
23 | #endif | 23 | #endif |
24 | 24 | ||
25 | #define NUMBER_NOPS 6 | 25 | #define NUMBER_NOPS 6 |
26 | #define CYCLES_PER_SEC (STM32_SYSCLK / NUMBER_NOPS * NOP_FUDGE) | 26 | #define CYCLES_PER_SEC (CPU_CLOCK / NUMBER_NOPS * NOP_FUDGE) |
27 | #define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives | 27 | #define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives |
28 | #define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC) | 28 | #define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC) |
29 | #define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE) | 29 | #define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE) |
diff --git a/platforms/chibios/drivers/ws2812_pwm.c b/platforms/chibios/drivers/ws2812_pwm.c index e6af55b6b..c17b9cd4e 100644 --- a/platforms/chibios/drivers/ws2812_pwm.c +++ b/platforms/chibios/drivers/ws2812_pwm.c | |||
@@ -5,7 +5,9 @@ | |||
5 | /* Adapted from https://github.com/joewa/WS2812-LED-Driver_ChibiOS/ */ | 5 | /* Adapted from https://github.com/joewa/WS2812-LED-Driver_ChibiOS/ */ |
6 | 6 | ||
7 | #ifdef RGBW | 7 | #ifdef RGBW |
8 | # error "RGBW not supported" | 8 | # define WS2812_CHANNELS 4 |
9 | #else | ||
10 | # define WS2812_CHANNELS 3 | ||
9 | #endif | 11 | #endif |
10 | 12 | ||
11 | #ifndef WS2812_PWM_DRIVER | 13 | #ifndef WS2812_PWM_DRIVER |
@@ -40,15 +42,15 @@ | |||
40 | // Default Push Pull | 42 | // Default Push Pull |
41 | #ifndef WS2812_EXTERNAL_PULLUP | 43 | #ifndef WS2812_EXTERNAL_PULLUP |
42 | # if defined(USE_GPIOV1) | 44 | # if defined(USE_GPIOV1) |
43 | # define WS2812_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 45 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE_PUSHPULL |
44 | # else | 46 | # else |
45 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUPDR_FLOATING | 47 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST | PAL_PUPDR_FLOATING |
46 | # endif | 48 | # endif |
47 | #else | 49 | #else |
48 | # if defined(USE_GPIOV1) | 50 | # if defined(USE_GPIOV1) |
49 | # define WS2812_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN | 51 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE_OPENDRAIN |
50 | # else | 52 | # else |
51 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUPDR_FLOATING | 53 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN | PAL_OUTPUT_SPEED_HIGHEST | PAL_PUPDR_FLOATING |
52 | # endif | 54 | # endif |
53 | #endif | 55 | #endif |
54 | 56 | ||
@@ -59,7 +61,7 @@ | |||
59 | 61 | ||
60 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ | 62 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ |
61 | 63 | ||
62 | #define WS2812_PWM_FREQUENCY (STM32_SYSCLK / 2) /**< Clock frequency of PWM, must be valid with respect to system clock! */ | 64 | #define WS2812_PWM_FREQUENCY (CPU_CLOCK / 2) /**< Clock frequency of PWM, must be valid with respect to system clock! */ |
63 | #define WS2812_PWM_PERIOD (WS2812_PWM_FREQUENCY / WS2812_PWM_TARGET_PERIOD) /**< Clock period in ticks. 1 / 800kHz = 1.25 uS (as per datasheet) */ | 65 | #define WS2812_PWM_PERIOD (WS2812_PWM_FREQUENCY / WS2812_PWM_TARGET_PERIOD) /**< Clock period in ticks. 1 / 800kHz = 1.25 uS (as per datasheet) */ |
64 | 66 | ||
65 | /** | 67 | /** |
@@ -68,8 +70,9 @@ | |||
68 | * The reset period for each frame is defined in WS2812_TRST_US. | 70 | * The reset period for each frame is defined in WS2812_TRST_US. |
69 | * Calculate the number of zeroes to add at the end assuming 1.25 uS/bit: | 71 | * Calculate the number of zeroes to add at the end assuming 1.25 uS/bit: |
70 | */ | 72 | */ |
73 | #define WS2812_COLOR_BITS (WS2812_CHANNELS * 8) | ||
71 | #define WS2812_RESET_BIT_N (1000 * WS2812_TRST_US / 1250) | 74 | #define WS2812_RESET_BIT_N (1000 * WS2812_TRST_US / 1250) |
72 | #define WS2812_COLOR_BIT_N (RGBLED_NUM * 24) /**< Number of data bits */ | 75 | #define WS2812_COLOR_BIT_N (RGBLED_NUM * WS2812_COLOR_BITS) /**< Number of data bits */ |
73 | #define WS2812_BIT_N (WS2812_COLOR_BIT_N + WS2812_RESET_BIT_N) /**< Total number of bits in a frame */ | 76 | #define WS2812_BIT_N (WS2812_COLOR_BIT_N + WS2812_RESET_BIT_N) /**< Total number of bits in a frame */ |
74 | 77 | ||
75 | /** | 78 | /** |
@@ -114,7 +117,7 @@ | |||
114 | * | 117 | * |
115 | * @return The bit index | 118 | * @return The bit index |
116 | */ | 119 | */ |
117 | #define WS2812_BIT(led, byte, bit) (24 * (led) + 8 * (byte) + (7 - (bit))) | 120 | #define WS2812_BIT(led, byte, bit) (WS2812_COLOR_BITS * (led) + 8 * (byte) + (7 - (bit))) |
118 | 121 | ||
119 | #if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) | 122 | #if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) |
120 | /** | 123 | /** |
@@ -228,6 +231,20 @@ | |||
228 | # define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 0, (bit)) | 231 | # define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 0, (bit)) |
229 | #endif | 232 | #endif |
230 | 233 | ||
234 | #ifdef RGBW | ||
235 | /** | ||
236 | * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given white bit | ||
237 | * | ||
238 | * @note The white byte is the last byte in the color packet | ||
239 | * | ||
240 | * @param[in] led: The led index [0, @ref WS2812_LED_N) | ||
241 | * @param[in] bit: The bit index [0, 7] | ||
242 | * | ||
243 | * @return The bit index | ||
244 | */ | ||
245 | # define WS2812_WHITE_BIT(led, bit) WS2812_BIT((led), 3, (bit)) | ||
246 | #endif | ||
247 | |||
231 | /* --- PRIVATE VARIABLES ---------------------------------------------------- */ | 248 | /* --- PRIVATE VARIABLES ---------------------------------------------------- */ |
232 | 249 | ||
233 | static uint32_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */ | 250 | static uint32_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */ |
@@ -296,6 +313,17 @@ void ws2812_write_led(uint16_t led_number, uint8_t r, uint8_t g, uint8_t b) { | |||
296 | ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; | 313 | ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; |
297 | } | 314 | } |
298 | } | 315 | } |
316 | void ws2812_write_led_rgbw(uint16_t led_number, uint8_t r, uint8_t g, uint8_t b, uint8_t w) { | ||
317 | // Write color to frame buffer | ||
318 | for (uint8_t bit = 0; bit < 8; bit++) { | ||
319 | ws2812_frame_buffer[WS2812_RED_BIT(led_number, bit)] = ((r >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; | ||
320 | ws2812_frame_buffer[WS2812_GREEN_BIT(led_number, bit)] = ((g >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; | ||
321 | ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; | ||
322 | #ifdef RGBW | ||
323 | ws2812_frame_buffer[WS2812_WHITE_BIT(led_number, bit)] = ((w >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; | ||
324 | #endif | ||
325 | } | ||
326 | } | ||
299 | 327 | ||
300 | // Setleds for standard RGB | 328 | // Setleds for standard RGB |
301 | void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { | 329 | void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { |
@@ -306,6 +334,10 @@ void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { | |||
306 | } | 334 | } |
307 | 335 | ||
308 | for (uint16_t i = 0; i < leds; i++) { | 336 | for (uint16_t i = 0; i < leds; i++) { |
337 | #ifdef RGBW | ||
338 | ws2812_write_led_rgbw(i, ledarray[i].r, ledarray[i].g, ledarray[i].b, ledarray[i].w); | ||
339 | #else | ||
309 | ws2812_write_led(i, ledarray[i].r, ledarray[i].g, ledarray[i].b); | 340 | ws2812_write_led(i, ledarray[i].r, ledarray[i].g, ledarray[i].b); |
341 | #endif | ||
310 | } | 342 | } |
311 | } | 343 | } |
diff --git a/platforms/chibios/drivers/ws2812_spi.c b/platforms/chibios/drivers/ws2812_spi.c index fe14b478a..62722f466 100644 --- a/platforms/chibios/drivers/ws2812_spi.c +++ b/platforms/chibios/drivers/ws2812_spi.c | |||
@@ -3,10 +3,6 @@ | |||
3 | 3 | ||
4 | /* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */ | 4 | /* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */ |
5 | 5 | ||
6 | #ifdef RGBW | ||
7 | # error "RGBW not supported" | ||
8 | #endif | ||
9 | |||
10 | // Define the spi your LEDs are plugged to here | 6 | // Define the spi your LEDs are plugged to here |
11 | #ifndef WS2812_SPI | 7 | #ifndef WS2812_SPI |
12 | # define WS2812_SPI SPID1 | 8 | # define WS2812_SPI SPID1 |
@@ -24,15 +20,15 @@ | |||
24 | // Default Push Pull | 20 | // Default Push Pull |
25 | #ifndef WS2812_EXTERNAL_PULLUP | 21 | #ifndef WS2812_EXTERNAL_PULLUP |
26 | # if defined(USE_GPIOV1) | 22 | # if defined(USE_GPIOV1) |
27 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 23 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE_PUSHPULL |
28 | # else | 24 | # else |
29 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | 25 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL |
30 | # endif | 26 | # endif |
31 | #else | 27 | #else |
32 | # if defined(USE_GPIOV1) | 28 | # if defined(USE_GPIOV1) |
33 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN | 29 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE_OPENDRAIN |
34 | # else | 30 | # else |
35 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN | 31 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN |
36 | # endif | 32 | # endif |
37 | #endif | 33 | #endif |
38 | 34 | ||
@@ -68,14 +64,18 @@ | |||
68 | #endif | 64 | #endif |
69 | 65 | ||
70 | #if defined(USE_GPIOV1) | 66 | #if defined(USE_GPIOV1) |
71 | # define WS2812_SCK_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 67 | # define WS2812_SCK_OUTPUT_MODE PAL_MODE_ALTERNATE_PUSHPULL |
72 | #else | 68 | #else |
73 | # define WS2812_SCK_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | 69 | # define WS2812_SCK_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL |
74 | #endif | 70 | #endif |
75 | 71 | ||
76 | #define BYTES_FOR_LED_BYTE 4 | 72 | #define BYTES_FOR_LED_BYTE 4 |
77 | #define NB_COLORS 3 | 73 | #ifdef RGBW |
78 | #define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS) | 74 | # define WS2812_CHANNELS 4 |
75 | #else | ||
76 | # define WS2812_CHANNELS 3 | ||
77 | #endif | ||
78 | #define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * WS2812_CHANNELS) | ||
79 | #define DATA_SIZE (BYTES_FOR_LED * RGBLED_NUM) | 79 | #define DATA_SIZE (BYTES_FOR_LED * RGBLED_NUM) |
80 | #define RESET_SIZE (1000 * WS2812_TRST_US / (2 * 1250)) | 80 | #define RESET_SIZE (1000 * WS2812_TRST_US / (2 * 1250)) |
81 | #define PREAMBLE_SIZE 4 | 81 | #define PREAMBLE_SIZE 4 |
@@ -116,6 +116,9 @@ static void set_led_color_rgb(LED_TYPE color, int pos) { | |||
116 | for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j); | 116 | for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j); |
117 | for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.r, j); | 117 | for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.r, j); |
118 | #endif | 118 | #endif |
119 | #ifdef RGBW | ||
120 | for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 4 + j] = get_protocol_eq(color.w, j); | ||
121 | #endif | ||
119 | } | 122 | } |
120 | 123 | ||
121 | void ws2812_init(void) { | 124 | void ws2812_init(void) { |
diff --git a/platforms/chibios/flash.mk b/platforms/chibios/flash.mk index c0b32c2f2..31f69595d 100644 --- a/platforms/chibios/flash.mk +++ b/platforms/chibios/flash.mk | |||
@@ -82,6 +82,8 @@ else ifeq ($(strip $(MCU_FAMILY)),MIMXRT1062) | |||
82 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_TEENSY) | 82 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_TEENSY) |
83 | else ifeq ($(strip $(MCU_FAMILY)),STM32) | 83 | else ifeq ($(strip $(MCU_FAMILY)),STM32) |
84 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL) | 84 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL) |
85 | else ifeq ($(strip $(MCU_FAMILY)),GD32V) | ||
86 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL) | ||
85 | else | 87 | else |
86 | $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_BOOTLOADER)" | 88 | $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_BOOTLOADER)" |
87 | endif | 89 | endif |