diff options
Diffstat (limited to 'tmk_core/common')
-rw-r--r-- | tmk_core/common/avr/bootloader.c | 10 | ||||
-rw-r--r-- | tmk_core/common/keyboard.c | 37 | ||||
-rw-r--r-- | tmk_core/common/keyboard.h | 9 | ||||
-rw-r--r-- | tmk_core/common/matrix.h | 3 | ||||
-rw-r--r-- | tmk_core/common/mousekey.c | 80 | ||||
-rw-r--r-- | tmk_core/common/mousekey.h | 43 | ||||
-rw-r--r-- | tmk_core/common/sync_timer.c | 58 | ||||
-rw-r--r-- | tmk_core/common/sync_timer.h | 54 | ||||
-rw-r--r-- | tmk_core/common/wait.h | 79 |
9 files changed, 354 insertions, 19 deletions
diff --git a/tmk_core/common/avr/bootloader.c b/tmk_core/common/avr/bootloader.c index a1db55da93..4e3a27022d 100644 --- a/tmk_core/common/avr/bootloader.c +++ b/tmk_core/common/avr/bootloader.c @@ -77,7 +77,7 @@ uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;"))); * * FIXME: needs doc */ -void bootloader_jump(void) { +__attribute__((weak)) void bootloader_jump(void) { #if !defined(BOOTLOADER_SIZE) uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); @@ -237,13 +237,13 @@ void bootloader_jump(void) { "bootloader_startup_loop%=: \n\t" "rjmp bootloader_startup_loop%= \n\t" : - : [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)), + : [ mcucsrio ] "I"(_SFR_IO_ADDR(MCUCSR)), # if (FLASHEND > 131071) - [ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff), + [ ramendhi ] "M"(((RAMEND - 2) >> 8) & 0xff), [ ramendlo ] "M"(((RAMEND - 2) >> 0) & 0xff), [ bootaddrhi ] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff), # else - [ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff), + [ ramendhi ] "M"(((RAMEND - 1) >> 8) & 0xff), [ ramendlo ] "M"(((RAMEND - 1) >> 0) & 0xff), # endif - [bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff)); + [ bootaddrme ] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [ bootaddrlo ] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff)); #else // Assume remaining boards are DFU, even if the flag isn't set diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c index 8c7bdc8b55..0ca4546128 100644 --- a/tmk_core/common/keyboard.c +++ b/tmk_core/common/keyboard.c @@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "led.h" #include "keycode.h" #include "timer.h" +#include "sync_timer.h" #include "print.h" #include "debug.h" #include "command.h" @@ -96,6 +97,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. # include "dip_switch.h" #endif +static uint32_t last_input_modification_time = 0; +uint32_t last_input_activity_time(void) { return last_input_modification_time; } +uint32_t last_input_activity_elapsed(void) { return timer_elapsed32(last_input_modification_time); } + +static uint32_t last_matrix_modification_time = 0; +uint32_t last_matrix_activity_time(void) { return last_matrix_modification_time; } +uint32_t last_matrix_activity_elapsed(void) { return timer_elapsed32(last_matrix_modification_time); } +void last_matrix_activity_trigger(void) { last_matrix_modification_time = last_input_modification_time = timer_read32(); } + +static uint32_t last_encoder_modification_time = 0; +uint32_t last_encoder_activity_time(void) { return last_encoder_modification_time; } +uint32_t last_encoder_activity_elapsed(void) { return timer_elapsed32(last_encoder_modification_time); } +void last_encoder_activity_trigger(void) { last_encoder_modification_time = last_input_modification_time = timer_read32(); } + // Only enable this if console is enabled to print to #if defined(DEBUG_MATRIX_SCAN_RATE) && defined(CONSOLE_ENABLE) static uint32_t matrix_timer = 0; @@ -255,6 +270,7 @@ __attribute__((weak)) void housekeeping_task_user(void) {} */ void keyboard_init(void) { timer_init(); + sync_timer_init(); matrix_init(); #ifdef VIA_ENABLE via_init(); @@ -332,15 +348,15 @@ void keyboard_task(void) { #ifdef QMK_KEYS_PER_SCAN uint8_t keys_processed = 0; #endif +#ifdef ENCODER_ENABLE + bool encoders_changed = false; +#endif housekeeping_task_kb(); housekeeping_task_user(); -#if defined(OLED_DRIVER_ENABLE) && !defined(OLED_DISABLE_TIMEOUT) - uint8_t ret = matrix_scan(); -#else - matrix_scan(); -#endif + uint8_t matrix_changed = matrix_scan(); + if (matrix_changed) last_matrix_activity_trigger(); if (should_process_keypress()) { for (uint8_t r = 0; r < MATRIX_ROWS; r++) { @@ -396,7 +412,8 @@ MATRIX_LOOP_END: #endif #ifdef ENCODER_ENABLE - encoder_read(); + encoders_changed = encoder_read(); + if (encoders_changed) last_encoder_activity_trigger(); #endif #ifdef QWIIC_ENABLE @@ -406,8 +423,12 @@ MATRIX_LOOP_END: #ifdef OLED_DRIVER_ENABLE oled_task(); # ifndef OLED_DISABLE_TIMEOUT - // Wake up oled if user is using those fabulous keys! - if (ret) oled_on(); + // Wake up oled if user is using those fabulous keys or spinning those encoders! +# ifdef ENCODER_ENABLE + if (matrix_changed || encoders_changed) oled_on(); +# else + if (matrix_changed) oled_on(); +# endif # endif #endif diff --git a/tmk_core/common/keyboard.h b/tmk_core/common/keyboard.h index d04e685cdb..88b3896e9e 100644 --- a/tmk_core/common/keyboard.h +++ b/tmk_core/common/keyboard.h @@ -73,6 +73,15 @@ void keyboard_post_init_user(void); void housekeeping_task_kb(void); void housekeeping_task_user(void); +uint32_t last_input_activity_time(void); // Timestamp of the last matrix or encoder activity +uint32_t last_input_activity_elapsed(void); // Number of milliseconds since the last matrix or encoder activity + +uint32_t last_matrix_activity_time(void); // Timestamp of the last matrix activity +uint32_t last_matrix_activity_elapsed(void); // Number of milliseconds since the last matrix activity + +uint32_t last_encoder_activity_time(void); // Timestamp of the last encoder activity +uint32_t last_encoder_activity_elapsed(void); // Number of milliseconds since the last encoder activity + #ifdef __cplusplus } #endif diff --git a/tmk_core/common/matrix.h b/tmk_core/common/matrix.h index b570227a31..ce57010a47 100644 --- a/tmk_core/common/matrix.h +++ b/tmk_core/common/matrix.h @@ -55,6 +55,9 @@ matrix_row_t matrix_get_row(uint8_t row); /* print matrix for debug */ void matrix_print(void); /* delay between changing matrix pin state and reading values */ +void matrix_output_select_delay(void); +void matrix_output_unselect_delay(void); +/* only for backwards compatibility. delay between changing matrix pin state and reading values */ void matrix_io_delay(void); /* power control */ diff --git a/tmk_core/common/mousekey.c b/tmk_core/common/mousekey.c index ef18bcf1a8..6c9df67236 100644 --- a/tmk_core/common/mousekey.c +++ b/tmk_core/common/mousekey.c @@ -36,6 +36,9 @@ static void mousekey_debug(void); static uint8_t mousekey_accel = 0; static uint8_t mousekey_repeat = 0; static uint8_t mousekey_wheel_repeat = 0; +#ifdef MK_KINETIC_SPEED +static uint16_t mouse_timer = 0; +#endif #ifndef MK_3_SPEED @@ -43,7 +46,7 @@ static uint16_t last_timer_c = 0; static uint16_t last_timer_w = 0; /* - * Mouse keys acceleration algorithm + * Mouse keys acceleration algorithm * http://en.wikipedia.org/wiki/Mouse_keys * * speed = delta * max_speed * (repeat / time_to_max)**((1000+curve)/1000) @@ -105,6 +108,65 @@ static uint8_t wheel_unit(void) { } # else /* #ifndef MK_COMBINED */ +# ifndef MK_KINETIC_SPEED + +/* + * Kinetic movement acceleration algorithm + * + * current speed = I + A * T/50 + A * 0.5 * T^2 | maximum B + * + * T: time since the mouse movement started + * E: mouse events per second (set through MOUSEKEY_INTERVAL, UHK sends 250, the + * pro micro on my Signum 3.0 sends only 125!) + * I: initial speed at time 0 + * A: acceleration + * B: base mouse travel speed + */ +const uint16_t mk_accelerated_speed = MOUSEKEY_ACCELERATED_SPEED; +const uint16_t mk_base_speed = MOUSEKEY_BASE_SPEED; +const uint16_t mk_decelerated_speed = MOUSEKEY_DECELERATED_SPEED; +const uint16_t mk_initial_speed = MOUSEKEY_INITIAL_SPEED; + +static uint8_t move_unit(void) { + float speed = mk_initial_speed; + + if (mousekey_accel & ((1 << 0) | (1 << 2))) { + speed = mousekey_accel & (1 << 2) ? mk_accelerated_speed : mk_decelerated_speed; + } else if (mousekey_repeat && mouse_timer) { + const float time_elapsed = timer_elapsed(mouse_timer) / 50; + speed = mk_initial_speed + MOUSEKEY_MOVE_DELTA * time_elapsed + MOUSEKEY_MOVE_DELTA * 0.5 * time_elapsed * time_elapsed; + + speed = speed > mk_base_speed ? mk_base_speed : speed; + } + + /* convert speed to USB mouse speed 1 to 127 */ + speed = (uint8_t)(speed / (1000.0f / mk_interval)); + speed = speed < 1 ? 1 : speed; + + return speed > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : speed; +} + +float mk_wheel_interval = 1000.0f / MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; + +static uint8_t wheel_unit(void) { + float speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; + + if (mousekey_accel & ((1 << 0) | (1 << 2))) { + speed = mousekey_accel & (1 << 2) ? MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS : MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS; + } else if (mousekey_repeat && mouse_timer) { + if (mk_wheel_interval != MOUSEKEY_WHEEL_BASE_MOVEMENTS) { + const float time_elapsed = timer_elapsed(mouse_timer) / 50; + speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS + 1 * time_elapsed + 1 * 0.5 * time_elapsed * time_elapsed; + } + speed = speed > MOUSEKEY_WHEEL_BASE_MOVEMENTS ? MOUSEKEY_WHEEL_BASE_MOVEMENTS : speed; + } + + mk_wheel_interval = 1000.0f / speed; + + return 1; +} + +# else /* #ifndef MK_KINETIC_SPEED */ static uint8_t move_unit(void) { uint16_t unit; @@ -142,7 +204,8 @@ static uint8_t wheel_unit(void) { return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit)); } -# endif /* #ifndef MK_COMBINED */ +# endif /* #ifndef MK_KINETIC_SPEED */ +# endif /* #ifndef MK_COMBINED */ void mousekey_task(void) { // report cursor and scroll movement independently @@ -193,6 +256,12 @@ void mousekey_task(void) { } void mousekey_on(uint8_t code) { +# ifdef MK_KINETIC_SPEED + if (mouse_timer == 0) { + mouse_timer = timer_read(); + } +# endif /* #ifdef MK_KINETIC_SPEED */ + if (code == KC_MS_UP) mouse_report.y = move_unit() * -1; else if (code == KC_MS_DOWN) @@ -260,7 +329,12 @@ void mousekey_off(uint8_t code) { mousekey_accel &= ~(1 << 1); else if (code == KC_MS_ACCEL2) mousekey_accel &= ~(1 << 2); - if (mouse_report.x == 0 && mouse_report.y == 0) mousekey_repeat = 0; + if (mouse_report.x == 0 && mouse_report.y == 0) { + mousekey_repeat = 0; +# ifdef MK_KINETIC_SPEED + mouse_timer = 0; +# endif /* #ifdef MK_KINETIC_SPEED */ + } if (mouse_report.v == 0 && mouse_report.h == 0) mousekey_wheel_repeat = 0; } diff --git a/tmk_core/common/mousekey.h b/tmk_core/common/mousekey.h index 300d262f5d..52b8fe10e1 100644 --- a/tmk_core/common/mousekey.h +++ b/tmk_core/common/mousekey.h @@ -36,16 +36,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. # endif # ifndef MOUSEKEY_MOVE_DELTA -# define MOUSEKEY_MOVE_DELTA 5 +# ifndef MK_KINETIC_SPEED +# define MOUSEKEY_MOVE_DELTA 5 +# else +# define MOUSEKEY_MOVE_DELTA 25 +# endif # endif # ifndef MOUSEKEY_WHEEL_DELTA # define MOUSEKEY_WHEEL_DELTA 1 # endif # ifndef MOUSEKEY_DELAY -# define MOUSEKEY_DELAY 300 +# ifndef MK_KINETIC_SPEED +# define MOUSEKEY_DELAY 300 +# else +# define MOUSEKEY_DELAY 8 +# endif # endif # ifndef MOUSEKEY_INTERVAL -# define MOUSEKEY_INTERVAL 50 +# ifndef MK_KINETIC_SPEED +# define MOUSEKEY_INTERVAL 50 +# else +# define MOUSEKEY_INTERVAL 8 +# endif # endif # ifndef MOUSEKEY_MAX_SPEED # define MOUSEKEY_MAX_SPEED 10 @@ -66,6 +78,31 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. # define MOUSEKEY_WHEEL_TIME_TO_MAX 40 # endif +# ifndef MOUSEKEY_INITIAL_SPEED +# define MOUSEKEY_INITIAL_SPEED 100 +# endif +# ifndef MOUSEKEY_BASE_SPEED +# define MOUSEKEY_BASE_SPEED 1000 +# endif +# ifndef MOUSEKEY_DECELERATED_SPEED +# define MOUSEKEY_DECELERATED_SPEED 400 +# endif +# ifndef MOUSEKEY_ACCELERATED_SPEED +# define MOUSEKEY_ACCELERATED_SPEED 3000 +# endif +# ifndef MOUSEKEY_WHEEL_INITIAL_MOVEMENTS +# define MOUSEKEY_WHEEL_INITIAL_MOVEMENTS 16 +# endif +# ifndef MOUSEKEY_WHEEL_BASE_MOVEMENTS +# define MOUSEKEY_WHEEL_BASE_MOVEMENTS 32 +# endif +# ifndef MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS +# define MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS 48 +# endif +# ifndef MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS +# define MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS 8 +# endif + #else /* #ifndef MK_3_SPEED */ # ifndef MK_C_OFFSET_UNMOD diff --git a/tmk_core/common/sync_timer.c b/tmk_core/common/sync_timer.c new file mode 100644 index 0000000000..de24b463b6 --- /dev/null +++ b/tmk_core/common/sync_timer.c @@ -0,0 +1,58 @@ +/* +Copyright (C) 2020 Ryan Caltabiano <https://github.com/XScorpion2> + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +If you happen to meet one of the copyright holders in a bar you are obligated +to buy them one pint of beer. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "sync_timer.h" +#include "keyboard.h" + +#if defined(SPLIT_KEYBOARD) && !defined(DISABLE_SYNC_TIMER) +volatile int32_t sync_timer_ms; + +void sync_timer_init(void) { sync_timer_ms = 0; } + +void sync_timer_update(uint32_t time) { + if (is_keyboard_master()) return; + sync_timer_ms = time - timer_read32(); +} + +uint16_t sync_timer_read(void) { + if (is_keyboard_master()) return timer_read(); + return sync_timer_read32(); +} + +uint32_t sync_timer_read32(void) { + if (is_keyboard_master()) return timer_read32(); + return sync_timer_ms + timer_read32(); +} + +uint16_t sync_timer_elapsed(uint16_t last) { + if (is_keyboard_master()) return timer_elapsed(last); + return TIMER_DIFF_16(sync_timer_read(), last); +} + +uint32_t sync_timer_elapsed32(uint32_t last) { + if (is_keyboard_master()) return timer_elapsed32(last); + return TIMER_DIFF_32(sync_timer_read32(), last); +} +#endif diff --git a/tmk_core/common/sync_timer.h b/tmk_core/common/sync_timer.h new file mode 100644 index 0000000000..9ddef45bb2 --- /dev/null +++ b/tmk_core/common/sync_timer.h @@ -0,0 +1,54 @@ +/* +Copyright (C) 2020 Ryan Caltabiano <https://github.com/XScorpion2> + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +If you happen to meet one of the copyright holders in a bar you are obligated +to buy them one pint of beer. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once + +#include <stdint.h> +#include "timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(SPLIT_KEYBOARD) && !defined(DISABLE_SYNC_TIMER) +void sync_timer_init(void); +void sync_timer_update(uint32_t time); +uint16_t sync_timer_read(void); +uint32_t sync_timer_read32(void); +uint16_t sync_timer_elapsed(uint16_t last); +uint32_t sync_timer_elapsed32(uint32_t last); +#else +# define sync_timer_init() +# define sync_timer_clear() +# define sync_timer_update(t) +# define sync_timer_read() timer_read() +# define sync_timer_read32() timer_read32() +# define sync_timer_elapsed(t) timer_elapsed(t) +# define sync_timer_elapsed32(t) timer_elapsed32(t) +#endif + +#ifdef __cplusplus +} +#endif diff --git a/tmk_core/common/wait.h b/tmk_core/common/wait.h index 89128e9daf..28224fe3aa 100644 --- a/tmk_core/common/wait.h +++ b/tmk_core/common/wait.h @@ -6,10 +6,89 @@ 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 <util/delay.h> # 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 <ch.h> # define wait_ms(ms) \ |