aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Arlott <70171+nomis@users.noreply.github.com>2021-08-20 00:31:23 +0100
committerGitHub <noreply@github.com>2021-08-20 00:31:23 +0100
commit0a1bf7f6aa6e44557041e03f6e58df5a180c6d79 (patch)
treec2883c302bd9f0d49b4f086763386399ef58b3d2
parent462e7f075a14175be08f32561d5ba783e725ab7c (diff)
downloadqmk_firmware-0a1bf7f6aa6e44557041e03f6e58df5a180c6d79.tar.gz
qmk_firmware-0a1bf7f6aa6e44557041e03f6e58df5a180c6d79.zip
Support using a timer for wait_us() on ChibiOS-based boards (#12211)
* Support using a timer for wait_us() on ChibiOS-based boards (#12198) There are spare GPT timers that can be used to get a more accurate wait_ms() time. This is required for the matrix scan unselect delay (30µs) to be shorter than the system tick rate of 100µs. This is limited to the maximum GPT duration of 65535 so values above that will automatically use the previous implementation based on the system tick. Using a specific timer means it can't be shared by another thread at the same time so when wait_us() is called from anything other than the main thread it will use the system tick implementation too. * Update tmk_core/common/chibios/wait.c * Update tmk_core/common/chibios/wait.c Co-authored-by: Joel Challis <git@zvecr.com>
-rw-r--r--tmk_core/chibios.mk3
-rw-r--r--tmk_core/common/chibios/_wait.c89
-rw-r--r--tmk_core/common/chibios/_wait.h24
-rw-r--r--tmk_core/common/chibios/wait.c90
4 files changed, 127 insertions, 79 deletions
diff --git a/tmk_core/chibios.mk b/tmk_core/chibios.mk
index 7962516a0..18839710b 100644
--- a/tmk_core/chibios.mk
+++ b/tmk_core/chibios.mk
@@ -211,7 +211,8 @@ CHIBISRC = $(STARTUPSRC) \
211 $(BOARDSRC) \ 211 $(BOARDSRC) \
212 $(STREAMSSRC) \ 212 $(STREAMSSRC) \
213 $(CHIBIOS)/os/various/syscalls.c \ 213 $(CHIBIOS)/os/various/syscalls.c \
214 $(PLATFORM_COMMON_DIR)/syscall-fallbacks.c 214 $(PLATFORM_COMMON_DIR)/syscall-fallbacks.c \
215 $(PLATFORM_COMMON_DIR)/wait.c
215 216
216# Ensure the ASM files are not subjected to LTO -- it'll strip out interrupt handlers otherwise. 217# Ensure the ASM files are not subjected to LTO -- it'll strip out interrupt handlers otherwise.
217QUANTUM_LIB_SRC += $(STARTUPASM) $(PORTASM) $(OSALASM) $(PLATFORMASM) 218QUANTUM_LIB_SRC += $(STARTUPASM) $(PORTASM) $(OSALASM) $(PLATFORMASM)
diff --git a/tmk_core/common/chibios/_wait.c b/tmk_core/common/chibios/_wait.c
new file mode 100644
index 000000000..1fbea2dd5
--- /dev/null
+++ b/tmk_core/common/chibios/_wait.c
@@ -0,0 +1,89 @@
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 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 <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef __OPTIMIZE__
18# pragma message "Compiler optimizations disabled; wait_cpuclock() won't work as designed"
19#endif
20
21#define CLOCK_DELAY_NOP8 "nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t"
22
23__attribute__((always_inline)) static inline void wait_cpuclock(unsigned int n) { /* n: 1..135 */
24 /* The argument n must be a constant expression.
25 * That way, compiler optimization will remove unnecessary code. */
26 if (n < 1) {
27 return;
28 }
29 if (n > 8) {
30 unsigned int n8 = n / 8;
31 n = n - n8 * 8;
32 switch (n8) {
33 case 16:
34 asm volatile(CLOCK_DELAY_NOP8::: "memory");
35 case 15:
36 asm volatile(CLOCK_DELAY_NOP8::: "memory");
37 case 14:
38 asm volatile(CLOCK_DELAY_NOP8::: "memory");
39 case 13:
40 asm volatile(CLOCK_DELAY_NOP8::: "memory");
41 case 12:
42 asm volatile(CLOCK_DELAY_NOP8::: "memory");
43 case 11:
44 asm volatile(CLOCK_DELAY_NOP8::: "memory");
45 case 10:
46 asm volatile(CLOCK_DELAY_NOP8::: "memory");
47 case 9:
48 asm volatile(CLOCK_DELAY_NOP8::: "memory");
49 case 8:
50 asm volatile(CLOCK_DELAY_NOP8::: "memory");
51 case 7:
52 asm volatile(CLOCK_DELAY_NOP8::: "memory");
53 case 6:
54 asm volatile(CLOCK_DELAY_NOP8::: "memory");
55 case 5:
56 asm volatile(CLOCK_DELAY_NOP8::: "memory");
57 case 4:
58 asm volatile(CLOCK_DELAY_NOP8::: "memory");
59 case 3:
60 asm volatile(CLOCK_DELAY_NOP8::: "memory");
61 case 2:
62 asm volatile(CLOCK_DELAY_NOP8::: "memory");
63 case 1:
64 asm volatile(CLOCK_DELAY_NOP8::: "memory");
65 case 0:
66 break;
67 }
68 }
69 switch (n) {
70 case 8:
71 asm volatile("nop" ::: "memory");
72 case 7:
73 asm volatile("nop" ::: "memory");
74 case 6:
75 asm volatile("nop" ::: "memory");
76 case 5:
77 asm volatile("nop" ::: "memory");
78 case 4:
79 asm volatile("nop" ::: "memory");
80 case 3:
81 asm volatile("nop" ::: "memory");
82 case 2:
83 asm volatile("nop" ::: "memory");
84 case 1:
85 asm volatile("nop" ::: "memory");
86 case 0:
87 break;
88 }
89}
diff --git a/tmk_core/common/chibios/_wait.h b/tmk_core/common/chibios/_wait.h
index 5bface53e..4a5172536 100644
--- a/tmk_core/common/chibios/_wait.h
+++ b/tmk_core/common/chibios/_wait.h
@@ -16,6 +16,7 @@
16#pragma once 16#pragma once
17 17
18#include <ch.h> 18#include <ch.h>
19#include <hal.h>
19 20
20/* chThdSleepX of zero maps to infinite - so we map to a tiny delay to still yield */ 21/* chThdSleepX of zero maps to infinite - so we map to a tiny delay to still yield */
21#define wait_ms(ms) \ 22#define wait_ms(ms) \
@@ -26,14 +27,19 @@
26 chThdSleepMicroseconds(1); \ 27 chThdSleepMicroseconds(1); \
27 } \ 28 } \
28 } while (0) 29 } while (0)
29#define wait_us(us) \ 30
30 do { \ 31#ifdef WAIT_US_TIMER
31 if (us != 0) { \ 32void wait_us(uint16_t duration);
32 chThdSleepMicroseconds(us); \ 33#else
33 } else { \ 34# define wait_us(us) \
34 chThdSleepMicroseconds(1); \ 35 do { \
35 } \ 36 if (us != 0) { \
36 } while (0) 37 chThdSleepMicroseconds(us); \
38 } else { \
39 chThdSleepMicroseconds(1); \
40 } \
41 } while (0)
42#endif
37 43
38/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus 44/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus
39 * to which the GPIO is connected. 45 * to which the GPIO is connected.
@@ -46,7 +52,7 @@
46 * (A fairly large value of 0.25 microseconds is set.) 52 * (A fairly large value of 0.25 microseconds is set.)
47 */ 53 */
48 54
49#include "wait.c" 55#include "_wait.c"
50 56
51#ifndef GPIO_INPUT_PIN_DELAY 57#ifndef GPIO_INPUT_PIN_DELAY
52# define GPIO_INPUT_PIN_DELAY (STM32_SYSCLK / 1000000L / 4) 58# define GPIO_INPUT_PIN_DELAY (STM32_SYSCLK / 1000000L / 4)
diff --git a/tmk_core/common/chibios/wait.c b/tmk_core/common/chibios/wait.c
index c6270fd95..56fd6ffce 100644
--- a/tmk_core/common/chibios/wait.c
+++ b/tmk_core/common/chibios/wait.c
@@ -14,76 +14,28 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 15 */
16 16
17#ifndef __OPTIMIZE__ 17#include <ch.h>
18# pragma message "Compiler optimizations disabled; wait_cpuclock() won't work as designed" 18#include <hal.h>
19#endif
20 19
21#define CLOCK_DELAY_NOP8 "nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t" 20#include "_wait.h"
22 21
23__attribute__((always_inline)) static inline void wait_cpuclock(unsigned int n) { /* n: 1..135 */ 22#ifdef WAIT_US_TIMER
24 /* The argument n must be a constant expression. 23void wait_us(uint16_t duration) {
25 * That way, compiler optimization will remove unnecessary code. */ 24 static const GPTConfig gpt_cfg = {1000000, NULL, 0, 0}; /* 1MHz timer, no callback */
26 if (n < 1) { 25
27 return; 26 if (duration == 0) {
28 } 27 duration = 1;
29 if (n > 8) {
30 unsigned int n8 = n / 8;
31 n = n - n8 * 8;
32 switch (n8) {
33 case 16:
34 asm volatile(CLOCK_DELAY_NOP8::: "memory");
35 case 15:
36 asm volatile(CLOCK_DELAY_NOP8::: "memory");
37 case 14:
38 asm volatile(CLOCK_DELAY_NOP8::: "memory");
39 case 13:
40 asm volatile(CLOCK_DELAY_NOP8::: "memory");
41 case 12:
42 asm volatile(CLOCK_DELAY_NOP8::: "memory");
43 case 11:
44 asm volatile(CLOCK_DELAY_NOP8::: "memory");
45 case 10:
46 asm volatile(CLOCK_DELAY_NOP8::: "memory");
47 case 9:
48 asm volatile(CLOCK_DELAY_NOP8::: "memory");
49 case 8:
50 asm volatile(CLOCK_DELAY_NOP8::: "memory");
51 case 7:
52 asm volatile(CLOCK_DELAY_NOP8::: "memory");
53 case 6:
54 asm volatile(CLOCK_DELAY_NOP8::: "memory");
55 case 5:
56 asm volatile(CLOCK_DELAY_NOP8::: "memory");
57 case 4:
58 asm volatile(CLOCK_DELAY_NOP8::: "memory");
59 case 3:
60 asm volatile(CLOCK_DELAY_NOP8::: "memory");
61 case 2:
62 asm volatile(CLOCK_DELAY_NOP8::: "memory");
63 case 1:
64 asm volatile(CLOCK_DELAY_NOP8::: "memory");
65 case 0:
66 break;
67 }
68 } 28 }
69 switch (n) { 29
70 case 8: 30 /*
71 asm volatile("nop" ::: "memory"); 31 * Only use this timer on the main thread;
72 case 7: 32 * other threads need to use their own timer.
73 asm volatile("nop" ::: "memory"); 33 */
74 case 6: 34 if (chThdGetSelfX() == &ch.mainthread && duration < (1ULL << (sizeof(gptcnt_t) * 8))) {
75 asm volatile("nop" ::: "memory"); 35 gptStart(&WAIT_US_TIMER, &gpt_cfg);
76 case 5: 36 gptPolledDelay(&WAIT_US_TIMER, duration);
77 asm volatile("nop" ::: "memory"); 37 } else {
78 case 4: 38 chThdSleepMicroseconds(duration);
79 asm volatile("nop" ::: "memory");
80 case 3:
81 asm volatile("nop" ::: "memory");
82 case 2:
83 asm volatile("nop" ::: "memory");
84 case 1:
85 asm volatile("nop" ::: "memory");
86 case 0:
87 break;
88 } 39 }
89} \ No newline at end of file 40}
41#endif