aboutsummaryrefslogtreecommitdiff
path: root/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'platforms')
-rw-r--r--platforms/arm_atsam/flash.mk11
-rw-r--r--platforms/avr/drivers/analog.c23
-rw-r--r--platforms/avr/drivers/analog.h1
-rw-r--r--platforms/avr/drivers/audio_pwm.h17
-rw-r--r--platforms/avr/drivers/audio_pwm_hardware.c332
-rw-r--r--platforms/avr/drivers/i2c_master.c56
-rw-r--r--platforms/avr/drivers/i2c_master.h2
-rw-r--r--platforms/avr/drivers/ps2/ps2_io.c51
-rw-r--r--platforms/avr/drivers/ps2/ps2_usart.c227
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk9
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h28
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h23
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h355
-rw-r--r--platforms/chibios/boards/QMK_PROTON_C/configs/config.h9
-rw-r--r--platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk9
-rw-r--r--platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h23
-rw-r--r--platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h302
-rw-r--r--platforms/chibios/boards/common/ld/STM32F401xC.ld85
-rw-r--r--platforms/chibios/boards/common/ld/STM32F401xE.ld85
-rw-r--r--platforms/chibios/boards/common/ld/STM32F405xG.ld86
-rw-r--r--platforms/chibios/boards/common/ld/STM32F411xE.ld85
-rw-r--r--platforms/chibios/drivers/analog.c10
-rw-r--r--platforms/chibios/drivers/audio_dac.h126
-rw-r--r--platforms/chibios/drivers/audio_dac_additive.c335
-rw-r--r--platforms/chibios/drivers/audio_dac_basic.c245
-rw-r--r--platforms/chibios/drivers/audio_pwm.h40
-rw-r--r--platforms/chibios/drivers/audio_pwm_hardware.c144
-rw-r--r--platforms/chibios/drivers/audio_pwm_software.c164
-rw-r--r--platforms/chibios/drivers/i2c_master.c37
-rw-r--r--platforms/chibios/drivers/i2c_master.h27
-rw-r--r--platforms/chibios/drivers/ps2/ps2_io.c55
-rw-r--r--platforms/chibios/drivers/serial.c2
-rw-r--r--platforms/chibios/drivers/serial_usart.c10
-rw-r--r--platforms/chibios/drivers/spi_master.c31
-rw-r--r--platforms/chibios/drivers/spi_master.h6
-rw-r--r--platforms/chibios/drivers/uart.c8
-rw-r--r--platforms/chibios/drivers/ws2812.c4
-rw-r--r--platforms/chibios/drivers/ws2812_pwm.c48
-rw-r--r--platforms/chibios/drivers/ws2812_spi.c27
-rw-r--r--platforms/chibios/flash.mk2
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
6MDLOADER_CLI ?= mdloader
7
8define EXEC_MDLOADER
9 $(MDLOADER_CLI) --first --download $(BUILD_DIR)/$(TARGET).bin --restart
10endef
11
12mdloader: bin
13 $(call EXEC_MDLOADER)
14
6flash: bin 15flash: bin
7ifneq ($(strip $(PROGRAM_CMD)),) 16ifneq ($(strip $(PROGRAM_CMD)),)
8 $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD) 17 $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD)
18else ifeq ($(strip $(ARM_ATSAM)),SAMD51J18A)
19 $(UNSYNC_OUTPUT_CMD) && $(call EXEC_MDLOADER)
9else 20else
10 $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_ARCH)" 21 $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_ARCH)"
11endif 22endif
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
24void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); } 24void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); }
25 25
26// Arduino compatible pin input
27int16_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
49int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); } 26int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); }
50 27
51uint8_t pinToMux(pin_t pin) { 28uint8_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 @@
23extern "C" { 23extern "C" {
24#endif 24#endif
25void analogReference(uint8_t mode); 25void analogReference(uint8_t mode);
26int16_t analogRead(uint8_t pin);
27 26
28int16_t analogReadPin(pin_t pin); 27int16_t analogReadPin(pin_t pin);
29uint8_t pinToMux(pin_t pin); 28uint8_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
26extern bool playing_note;
27extern bool playing_melody;
28extern 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
153static float channel_1_frequency = 0.0f;
154void 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
174void 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
181void 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
190static float channel_2_frequency = 0.0f;
191void 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
205float channel_2_get_frequency(void) { return channel_2_frequency; }
206
207void channel_2_start(void) {
208 AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy);
209 AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
210}
211
212void channel_2_stop(void) {
213 AUDIO2_TIMSKx &= ~_BV(AUDIO2_OCIExy);
214 AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
215}
216#endif
217
218void 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
259void 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
269void 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
285static volatile uint32_t isr_counter = 0;
286#ifdef AUDIO1_PIN_SET
287ISR(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)
316ISR(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
205i2c_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
205i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { 224i2c_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
257i2c_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
288error:
289 i2c_stop();
290
291 return (status < 0) ? status : I2C_STATUS_SUCCESS;
292}
293
238void i2c_stop(void) { 294void 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);
39i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); 39i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
40i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); 40i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
41i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); 41i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
42i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
42i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); 43i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
44i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
43void i2c_stop(void); 45void 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 */
18void clock_init(void) {}
19
20void 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
26void clock_hi(void) { setPinInputHigh(PS2_CLOCK_PIN); }
27
28bool clock_in(void) {
29 setPinInputHigh(PS2_CLOCK_PIN);
30 wait_us(1);
31 return readPin(PS2_CLOCK_PIN);
32}
33
34/*
35 * Data
36 */
37void data_init(void) {}
38
39void 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
45void data_hi(void) { setPinInputHigh(PS2_DATA_PIN); }
46
47bool 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/*
2Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3
4This software is licensed with a Modified BSD License.
5All of this is supposed to be Free Software, Open Source, DFSG-free,
6GPL-compatible, and OK to use in both free and proprietary applications.
7Additions and corrections to this file are welcome.
8
9
10Redistribution and use in source and binary forms, with or without
11modification, 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
25THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35POSSIBILITY 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
71uint8_t ps2_error = PS2_ERR_NONE;
72
73static inline uint8_t pbuf_dequeue(void);
74static inline void pbuf_enqueue(uint8_t data);
75static inline bool pbuf_has_data(void);
76static inline void pbuf_clear(void);
77
78void 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
86uint8_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();
140ERROR:
141 idle();
142 PS2_USART_INIT();
143 PS2_USART_RX_INT_ON();
144 return 0;
145}
146
147uint8_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
156uint8_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
166ISR(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 */
178void 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
187static uint8_t pbuf[PBUF_SIZE];
188static uint8_t pbuf_head = 0;
189static uint8_t pbuf_tail = 0;
190static 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}
202static 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}
215static 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}
222static 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.
2BOARDSRC = $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY/board.c
3
4# Required include directories
5BOARDINC = $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY
6
7# Shared variables
8ALLCSRC += $(BOARDSRC)
9ALLINC += $(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.
2BOARDSRC = ${CHIBIOS_CONTRIB}/os/hal/boards/SIPEED_LONGAN_NANO/board.c
3
4# Required include directories
5BOARDINC = ${CHIBIOS_CONTRIB}/os/hal/boards/SIPEED_LONGAN_NANO
6
7# Shared variables
8ALLCSRC += $(BOARDSRC)
9ALLINC += $(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)
20struct _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 */
20MEMORY
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.*/
44REGION_ALIAS("VECTORS_FLASH", flash0);
45REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
46
47/* Flash region to be used for constructors and destructors.*/
48REGION_ALIAS("XTORS_FLASH", flash2);
49REGION_ALIAS("XTORS_FLASH_LMA", flash2);
50
51/* Flash region to be used for code text.*/
52REGION_ALIAS("TEXT_FLASH", flash2);
53REGION_ALIAS("TEXT_FLASH_LMA", flash2);
54
55/* Flash region to be used for read only data.*/
56REGION_ALIAS("RODATA_FLASH", flash2);
57REGION_ALIAS("RODATA_FLASH_LMA", flash2);
58
59/* Flash region to be used for various.*/
60REGION_ALIAS("VARIOUS_FLASH", flash2);
61REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
62
63/* Flash region to be used for RAM(n) initialization data.*/
64REGION_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.*/
68REGION_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.*/
72REGION_ALIAS("PROCESS_STACK_RAM", ram0);
73
74/* RAM region to be used for data segment.*/
75REGION_ALIAS("DATA_RAM", ram0);
76REGION_ALIAS("DATA_RAM_LMA", flash2);
77
78/* RAM region to be used for BSS segment.*/
79REGION_ALIAS("BSS_RAM", ram0);
80
81/* RAM region to be used for the default heap.*/
82REGION_ALIAS("HEAP_RAM", ram0);
83
84/* Generic rules inclusion.*/
85INCLUDE 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 */
20MEMORY
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.*/
44REGION_ALIAS("VECTORS_FLASH", flash0);
45REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
46
47/* Flash region to be used for constructors and destructors.*/
48REGION_ALIAS("XTORS_FLASH", flash2);
49REGION_ALIAS("XTORS_FLASH_LMA", flash2);
50
51/* Flash region to be used for code text.*/
52REGION_ALIAS("TEXT_FLASH", flash2);
53REGION_ALIAS("TEXT_FLASH_LMA", flash2);
54
55/* Flash region to be used for read only data.*/
56REGION_ALIAS("RODATA_FLASH", flash2);
57REGION_ALIAS("RODATA_FLASH_LMA", flash2);
58
59/* Flash region to be used for various.*/
60REGION_ALIAS("VARIOUS_FLASH", flash2);
61REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
62
63/* Flash region to be used for RAM(n) initialization data.*/
64REGION_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.*/
68REGION_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.*/
72REGION_ALIAS("PROCESS_STACK_RAM", ram0);
73
74/* RAM region to be used for data segment.*/
75REGION_ALIAS("DATA_RAM", ram0);
76REGION_ALIAS("DATA_RAM_LMA", flash2);
77
78/* RAM region to be used for BSS segment.*/
79REGION_ALIAS("BSS_RAM", ram0);
80
81/* RAM region to be used for the default heap.*/
82REGION_ALIAS("HEAP_RAM", ram0);
83
84/* Generic rules inclusion.*/
85INCLUDE 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 */
21MEMORY
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.*/
45REGION_ALIAS("VECTORS_FLASH", flash0);
46REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
47
48/* Flash region to be used for constructors and destructors.*/
49REGION_ALIAS("XTORS_FLASH", flash2);
50REGION_ALIAS("XTORS_FLASH_LMA", flash2);
51
52/* Flash region to be used for code text.*/
53REGION_ALIAS("TEXT_FLASH", flash2);
54REGION_ALIAS("TEXT_FLASH_LMA", flash2);
55
56/* Flash region to be used for read only data.*/
57REGION_ALIAS("RODATA_FLASH", flash2);
58REGION_ALIAS("RODATA_FLASH_LMA", flash2);
59
60/* Flash region to be used for various.*/
61REGION_ALIAS("VARIOUS_FLASH", flash2);
62REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
63
64/* Flash region to be used for RAM(n) initialization data.*/
65REGION_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.*/
69REGION_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.*/
73REGION_ALIAS("PROCESS_STACK_RAM", ram0);
74
75/* RAM region to be used for data segment.*/
76REGION_ALIAS("DATA_RAM", ram0);
77REGION_ALIAS("DATA_RAM_LMA", flash2);
78
79/* RAM region to be used for BSS segment.*/
80REGION_ALIAS("BSS_RAM", ram0);
81
82/* RAM region to be used for the default heap.*/
83REGION_ALIAS("HEAP_RAM", ram0);
84
85/* Generic rules inclusion.*/
86INCLUDE 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 */
20MEMORY
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.*/
44REGION_ALIAS("VECTORS_FLASH", flash0);
45REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
46
47/* Flash region to be used for constructors and destructors.*/
48REGION_ALIAS("XTORS_FLASH", flash2);
49REGION_ALIAS("XTORS_FLASH_LMA", flash2);
50
51/* Flash region to be used for code text.*/
52REGION_ALIAS("TEXT_FLASH", flash2);
53REGION_ALIAS("TEXT_FLASH_LMA", flash2);
54
55/* Flash region to be used for read only data.*/
56REGION_ALIAS("RODATA_FLASH", flash2);
57REGION_ALIAS("RODATA_FLASH_LMA", flash2);
58
59/* Flash region to be used for various.*/
60REGION_ALIAS("VARIOUS_FLASH", flash2);
61REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
62
63/* Flash region to be used for RAM(n) initialization data.*/
64REGION_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.*/
68REGION_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.*/
72REGION_ALIAS("PROCESS_STACK_RAM", ram0);
73
74/* RAM region to be used for data segment.*/
75REGION_ALIAS("DATA_RAM", ram0);
76REGION_ALIAS("DATA_RAM_LMA", flash2);
77
78/* RAM region to be used for BSS segment.*/
79REGION_ALIAS("BSS_RAM", ram0);
80
81/* RAM region to be used for the default heap.*/
82REGION_ALIAS("HEAP_RAM", ram0);
83
84/* Generic rules inclusion.*/
85INCLUDE 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 */
126uint16_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 */
51static 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
57static 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
63static 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
70static 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
78static 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
82static 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 */
85static float dac_if[AUDIO_MAX_SIMULTANEOUS_TONES] = {0.0};
86
87static float active_tones_snapshot[AUDIO_MAX_SIMULTANEOUS_TONES] = {0, 0};
88static uint8_t active_tones_snapshot_length = 0;
89
90typedef 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;
104output_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 */
169static 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
254static void dac_error(DACDriver *dacp, dacerror_t err) {
255 (void)dacp;
256 (void)err;
257
258 chSysHalt("DAC failure. halp");
259}
260
261static 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
266static 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 */
282static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)};
283
284void 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
324void audio_driver_stop(void) { state = OUTPUT_SHOULD_STOP; }
325
326void 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
53static 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
60static 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
66GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE,
67 .callback = NULL,
68 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
69 .dier = 0U};
70GPTConfig 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
75static void gpt_audio_state_cb(GPTDriver *gptp);
76GPTConfig 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
81static const DACConfig dac_conf_ch1 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
82static 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 */
98static const DACConversionGroup dac_conv_grp_ch1 = {.num_channels = 1U, .trigger = DAC_TRG(0b000)};
99static const DACConversionGroup dac_conv_grp_ch2 = {.num_channels = 1U, .trigger = DAC_TRG(0b010)};
100
101void channel_1_start(void) {
102 gptStart(&GPTD6, &gpt6cfg1);
103 gptStartContinuous(&GPTD6, 2U);
104 palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
105}
106
107void channel_1_stop(void) {
108 gptStopTimer(&GPTD6);
109 palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL);
110 palSetPad(GPIOA, 4);
111}
112
113static float channel_1_frequency = 0.0f;
114void 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}
124float channel_1_get_frequency(void) { return channel_1_frequency; }
125
126void channel_2_start(void) {
127 gptStart(&GPTD7, &gpt7cfg1);
128 gptStartContinuous(&GPTD7, 2U);
129 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
130}
131
132void channel_2_stop(void) {
133 gptStopTimer(&GPTD7);
134 palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL);
135 palSetPad(GPIOA, 5);
136}
137
138static float channel_2_frequency = 0.0f;
139void 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}
149float channel_2_get_frequency(void) { return channel_2_frequency; }
150
151static 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
186void 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
219void 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
237void 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/*
19Audio Driver: PWM
20
21the 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
23this driver uses the chibios-PWM system to produce a square-wave on specific output pins that are connected to the PWM hardware.
24The 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
36extern bool playing_note;
37extern bool playing_melody;
38extern uint8_t note_timbre;
39
40static 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
71static float channel_1_frequency = 0.0f;
72void 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
85float channel_1_get_frequency(void) { return channel_1_frequency; }
86
87void channel_1_start(void) {
88 pwmStop(&AUDIO_PWM_DRIVER);
89 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
90}
91
92void channel_1_stop(void) { pwmStop(&AUDIO_PWM_DRIVER); }
93
94static void gpt_callback(GPTDriver *gptp);
95GPTConfig 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
107void 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
120void 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
129void 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 */
137static 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/*
19Audio Driver: PWM
20
21the 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
23this 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
34extern bool playing_note;
35extern bool playing_melody;
36extern uint8_t note_timbre;
37
38static void pwm_audio_period_callback(PWMDriver *pwmp);
39static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp);
40
41static 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
56static float channel_1_frequency = 0.0f;
57void 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
71float channel_1_get_frequency(void) { return channel_1_frequency; }
72
73void 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
81void 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
92static 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}
100static 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
110static void gpt_callback(GPTDriver *gptp);
111GPTConfig 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
123void 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
140void 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
149void 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 */
157static 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
114i2c_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
114i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { 129i2c_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
136i2c_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
121void i2c_stop(void) { i2cStop(&I2C_DRIVER); } 144void 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);
109i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); 96i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
110i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); 97i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
111i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); 98i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
99i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
112i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); 100i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
101i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
113void i2c_stop(void); 102void 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 */
20void clock_init(void) {}
21
22void clock_lo(void) {
23 palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
24 palWriteLine(PS2_CLOCK_PIN, PAL_LOW);
25}
26
27void clock_hi(void) {
28 palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
29 palWriteLine(PS2_CLOCK_PIN, PAL_HIGH);
30}
31
32bool clock_in(void) {
33 palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_INPUT);
34 return palReadLine(PS2_CLOCK_PIN);
35}
36
37/*
38 * Data
39 */
40void data_init(void) {}
41
42void data_lo(void) {
43 palSetLineMode(PS2_DATA_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
44 palWriteLine(PS2_DATA_PIN, PAL_LOW);
45}
46
47void data_hi(void) {
48 palSetLineMode(PS2_DATA_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
49 palWriteLine(PS2_DATA_PIN, PAL_HIGH);
50}
51
52bool 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
233static uint32_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */ 250static 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}
316void 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
301void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { 329void 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
121void ws2812_init(void) { 124void 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)
83else ifeq ($(strip $(MCU_FAMILY)),STM32) 83else ifeq ($(strip $(MCU_FAMILY)),STM32)
84 $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL) 84 $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
85else ifeq ($(strip $(MCU_FAMILY)),GD32V)
86 $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
85else 87else
86 $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_BOOTLOADER)" 88 $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_BOOTLOADER)"
87endif 89endif