Skip to content

Commit

Permalink
Support using a timer for wait_us() on ChibiOS-based boards (qmk#12198)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nomis authored and dkjer committed May 30, 2021
1 parent dec5a9e commit faece61
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
17 changes: 16 additions & 1 deletion tmk_core/common/chibios/_wait.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,29 @@
chThdSleepMicroseconds(1); \
} \
} while (0)
#define wait_us(us) \

#ifdef WAIT_US_TIMER
# include <hal.h>
# define wait_us(us) \
do { \
if (us == 0) { \
timer_wait_us(1); \
} else if (us < (1ULL << (sizeof(gptcnt_t) * 8))) { \
timer_wait_us(us); \
} else { \
chThdSleepMicroseconds(us); \
} \
} while (0)
#else
# define wait_us(us) \
do { \
if (us != 0) { \
chThdSleepMicroseconds(us); \
} else { \
chThdSleepMicroseconds(1); \
} \
} while (0)
#endif

/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus
* to which the GPIO is connected.
Expand Down
29 changes: 28 additions & 1 deletion tmk_core/common/chibios/timer.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <ch.h>
#include <hal.h>

#include "timer.h"

Expand All @@ -8,7 +9,18 @@ static uint32_t last_systime = 0;
static uint32_t overflow = 0;
#endif

void timer_init(void) { timer_clear(); }
#ifdef WAIT_US_TIMER
static thread_t *main_thread = NULL;
static const GPTConfig gpt_cfg = { 100000, NULL, 0, 0 }; /* 1MHz timer, no callback */
#endif

void timer_init(void) {
#ifdef WAIT_US_TIMER
main_thread = chThdGetSelfX();
#endif

timer_clear();
}

void timer_clear(void) {
reset_point = (uint32_t)chVTGetSystemTime();
Expand Down Expand Up @@ -45,3 +57,18 @@ uint32_t timer_read32(void) {
uint16_t timer_elapsed(uint16_t last) { return TIMER_DIFF_16(timer_read(), last); }

uint32_t timer_elapsed32(uint32_t last) { return TIMER_DIFF_32(timer_read32(), last); }

#ifdef WAIT_US_TIMER
void timer_wait_us(gptcnt_t duration) {
/*
* Only use this timer on the main thread;
* other threads need to use their own timer.
*/
if (chThdGetSelfX() == main_thread) {
gptStart(&WAIT_US_TIMER, &gpt_cfg);
gptPolledDelay(&WAIT_US_TIMER, duration);
} else {
chThdSleepMicroseconds(duration);
}
}
#endif
9 changes: 9 additions & 0 deletions tmk_core/common/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "avr/timer_avr.h"
#endif

#if defined(PROTOCOL_CHIBIOS)
# include <ch.h>
# include <hal.h>
#endif

#define TIMER_DIFF(a, b, max) ((max == UINT8_MAX) ? ((uint8_t)((a) - (b))) : ((max == UINT16_MAX) ? ((uint16_t)((a) - (b))) : ((max == UINT32_MAX) ? ((uint32_t)((a) - (b))) : ((a) >= (b) ? (a) - (b) : (max) + 1 - (b) + (a)))))
#define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX)
#define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX)
Expand All @@ -47,6 +52,10 @@ uint32_t timer_elapsed32(uint32_t last);
#define timer_expired(current, future) ((uint16_t)(current - future) < UINT16_MAX / 2)
#define timer_expired32(current, future) ((uint32_t)(current - future) < UINT32_MAX / 2)

#if defined(PROTOCOL_CHIBIOS) && defined(WAIT_US_TIMER)
void timer_wait_us(gptcnt_t duration);
#endif

#ifdef __cplusplus
}
#endif

0 comments on commit faece61

Please sign in to comment.