From 40c7ecfdeaf50ab76e10854a84aebfcb82ddb092 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Wed, 10 Mar 2021 22:47:36 +0000 Subject: [PATCH] Move gpio wait logic to wait.h (#12067) --- quantum/quantum.h | 33 ------ tmk_core/common/arm_atsam/_wait.h | 22 ++++ tmk_core/common/avr/_wait.h | 29 ++++++ tmk_core/common/chibios/_wait.h | 55 ++++++++++ tmk_core/common/chibios/chibios_config.h | 1 + tmk_core/common/chibios/wait.c | 89 ++++++++++++++++ tmk_core/common/test/_wait.h | 22 ++++ tmk_core/common/wait.h | 125 +++-------------------- 8 files changed, 235 insertions(+), 141 deletions(-) create mode 100644 tmk_core/common/arm_atsam/_wait.h create mode 100644 tmk_core/common/avr/_wait.h create mode 100644 tmk_core/common/chibios/_wait.h create mode 100644 tmk_core/common/chibios/wait.c create mode 100644 tmk_core/common/test/_wait.h diff --git a/quantum/quantum.h b/quantum/quantum.h index 7c2dcaa829..7c546b5152 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -200,39 +200,6 @@ extern layer_state_t layer_state; # include "usbpd.h" #endif -// Function substitutions to ease GPIO manipulation -#if defined(__AVR__) - -/* The AVR series GPIOs have a one clock read delay for changes in the digital input signal. - * But here's more margin to make it two clocks. */ -# if !defined(GPIO_INPUT_PIN_DELAY) -# define GPIO_INPUT_PIN_DELAY 2 -# endif -# define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY) - -#elif defined(__ARMEL__) || defined(__ARMEB__) - -/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus - * to which the GPIO is connected. - * The connected buses differ depending on the various series of MCUs. - * And since the instruction execution clock of the CPU and the bus clock of GPIO are different, - * there is a delay of several clocks to read the change of the input signal. - * - * Define this delay with the GPIO_INPUT_PIN_DELAY macro. - * If the GPIO_INPUT_PIN_DELAY macro is not defined, the following default values will be used. - * (A fairly large value of 0.25 microseconds is set.) - */ -# if !defined(GPIO_INPUT_PIN_DELAY) -# if defined(STM32_SYSCLK) -# define GPIO_INPUT_PIN_DELAY (STM32_SYSCLK / 1000000L / 4) -# elif defined(KINETIS_SYSCLK_FREQUENCY) -# define GPIO_INPUT_PIN_DELAY (KINETIS_SYSCLK_FREQUENCY / 1000000L / 4) -# endif -# endif -# define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY) - -#endif - // For tri-layer void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3); diff --git a/tmk_core/common/arm_atsam/_wait.h b/tmk_core/common/arm_atsam/_wait.h new file mode 100644 index 0000000000..41b686b56c --- /dev/null +++ b/tmk_core/common/arm_atsam/_wait.h @@ -0,0 +1,22 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "clks.h" + +#define wait_ms(ms) CLK_delay_ms(ms) +#define wait_us(us) CLK_delay_us(us) +#define waitInputPinDelay() diff --git a/tmk_core/common/avr/_wait.h b/tmk_core/common/avr/_wait.h new file mode 100644 index 0000000000..56eb316faf --- /dev/null +++ b/tmk_core/common/avr/_wait.h @@ -0,0 +1,29 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +#define wait_ms(ms) _delay_ms(ms) +#define wait_us(us) _delay_us(us) + +/* The AVR series GPIOs have a one clock read delay for changes in the digital input signal. + * But here's more margin to make it two clocks. */ +#ifndef GPIO_INPUT_PIN_DELAY +# define GPIO_INPUT_PIN_DELAY 2 +#endif + +#define waitInputPinDelay() __builtin_avr_delay_cycles(GPIO_INPUT_PIN_DELAY) diff --git a/tmk_core/common/chibios/_wait.h b/tmk_core/common/chibios/_wait.h new file mode 100644 index 0000000000..5bface53e1 --- /dev/null +++ b/tmk_core/common/chibios/_wait.h @@ -0,0 +1,55 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +/* chThdSleepX of zero maps to infinite - so we map to a tiny delay to still yield */ +#define wait_ms(ms) \ + do { \ + if (ms != 0) { \ + chThdSleepMilliseconds(ms); \ + } else { \ + chThdSleepMicroseconds(1); \ + } \ + } while (0) +#define wait_us(us) \ + do { \ + if (us != 0) { \ + chThdSleepMicroseconds(us); \ + } else { \ + chThdSleepMicroseconds(1); \ + } \ + } while (0) + +/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus + * to which the GPIO is connected. + * The connected buses differ depending on the various series of MCUs. + * And since the instruction execution clock of the CPU and the bus clock of GPIO are different, + * there is a delay of several clocks to read the change of the input signal. + * + * Define this delay with the GPIO_INPUT_PIN_DELAY macro. + * If the GPIO_INPUT_PIN_DELAY macro is not defined, the following default values will be used. + * (A fairly large value of 0.25 microseconds is set.) + */ + +#include "wait.c" + +#ifndef GPIO_INPUT_PIN_DELAY +# define GPIO_INPUT_PIN_DELAY (STM32_SYSCLK / 1000000L / 4) +#endif + +#define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY) diff --git a/tmk_core/common/chibios/chibios_config.h b/tmk_core/common/chibios/chibios_config.h index bebf026de7..9a66ac3174 100644 --- a/tmk_core/common/chibios/chibios_config.h +++ b/tmk_core/common/chibios/chibios_config.h @@ -30,4 +30,5 @@ # define USE_I2CV1 # define USE_I2CV1_CONTRIB // for some reason a bunch of ChibiOS-Contrib boards only have clock_speed # define USE_GPIOV1 +# define STM32_SYSCLK KINETIS_SYSCLK_FREQUENCY #endif diff --git a/tmk_core/common/chibios/wait.c b/tmk_core/common/chibios/wait.c new file mode 100644 index 0000000000..c6270fd95e --- /dev/null +++ b/tmk_core/common/chibios/wait.c @@ -0,0 +1,89 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __OPTIMIZE__ +# pragma message "Compiler optimizations disabled; wait_cpuclock() won't work as designed" +#endif + +#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" + +__attribute__((always_inline)) static inline void wait_cpuclock(unsigned int n) { /* n: 1..135 */ + /* The argument n must be a constant expression. + * That way, compiler optimization will remove unnecessary code. */ + if (n < 1) { + return; + } + if (n > 8) { + unsigned int n8 = n / 8; + n = n - n8 * 8; + switch (n8) { + case 16: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 15: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 14: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 13: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 12: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 11: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 10: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 9: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 8: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 7: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 6: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 5: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 4: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 3: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 2: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 1: + asm volatile(CLOCK_DELAY_NOP8::: "memory"); + case 0: + break; + } + } + switch (n) { + case 8: + asm volatile("nop" ::: "memory"); + case 7: + asm volatile("nop" ::: "memory"); + case 6: + asm volatile("nop" ::: "memory"); + case 5: + asm volatile("nop" ::: "memory"); + case 4: + asm volatile("nop" ::: "memory"); + case 3: + asm volatile("nop" ::: "memory"); + case 2: + asm volatile("nop" ::: "memory"); + case 1: + asm volatile("nop" ::: "memory"); + case 0: + break; + } +} \ No newline at end of file diff --git a/tmk_core/common/test/_wait.h b/tmk_core/common/test/_wait.h new file mode 100644 index 0000000000..4e22f593b7 --- /dev/null +++ b/tmk_core/common/test/_wait.h @@ -0,0 +1,22 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +void wait_ms(uint32_t ms); +#define wait_us(us) wait_ms(us / 1000) +#define waitInputPinDelay() diff --git a/tmk_core/common/wait.h b/tmk_core/common/wait.h index 28224fe3aa..cf7180fb07 100644 --- a/tmk_core/common/wait.h +++ b/tmk_core/common/wait.h @@ -1,3 +1,18 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #pragma once #include @@ -6,114 +21,8 @@ extern "C" { #endif -#if defined(__ARMEL__) || defined(__ARMEB__) -# ifndef __OPTIMIZE__ -# pragma message "Compiler optimizations disabled; wait_cpuclock() won't work as designed" -# endif - -# define wait_cpuclock(x) wait_cpuclock_allnop(x) - -# 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" - -__attribute__((always_inline)) static inline void wait_cpuclock_allnop(unsigned int n) { /* n: 1..135 */ - /* The argument n must be a constant expression. - * That way, compiler optimization will remove unnecessary code. */ - if (n < 1) { - return; - } - if (n > 8) { - unsigned int n8 = n / 8; - n = n - n8 * 8; - switch (n8) { - case 16: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 15: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 14: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 13: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 12: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 11: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 10: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 9: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 8: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 7: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 6: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 5: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 4: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 3: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 2: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 1: - asm volatile(CLOCK_DELAY_NOP8::: "memory"); - case 0: - break; - } - } - switch (n) { - case 8: - asm volatile("nop" ::: "memory"); - case 7: - asm volatile("nop" ::: "memory"); - case 6: - asm volatile("nop" ::: "memory"); - case 5: - asm volatile("nop" ::: "memory"); - case 4: - asm volatile("nop" ::: "memory"); - case 3: - asm volatile("nop" ::: "memory"); - case 2: - asm volatile("nop" ::: "memory"); - case 1: - asm volatile("nop" ::: "memory"); - case 0: - break; - } -} -#endif - -#if defined(__AVR__) -# include -# define wait_ms(ms) _delay_ms(ms) -# define wait_us(us) _delay_us(us) -# define wait_cpuclock(x) __builtin_avr_delay_cycles(x) -#elif defined PROTOCOL_CHIBIOS -# include -# define wait_ms(ms) \ - do { \ - if (ms != 0) { \ - chThdSleepMilliseconds(ms); \ - } else { \ - chThdSleepMicroseconds(1); \ - } \ - } while (0) -# define wait_us(us) \ - do { \ - if (us != 0) { \ - chThdSleepMicroseconds(us); \ - } else { \ - chThdSleepMicroseconds(1); \ - } \ - } while (0) -#elif defined PROTOCOL_ARM_ATSAM -# include "clks.h" -# define wait_ms(ms) CLK_delay_ms(ms) -# define wait_us(us) CLK_delay_us(us) -#else // Unit tests -void wait_ms(uint32_t ms); -# define wait_us(us) wait_ms(us / 1000) +#if __has_include_next("_wait.h") +# include_next "_wait.h" /* Include the platforms _wait.h */ #endif #ifdef __cplusplus