From 0129a59f8604193cceeaf42b9014974017630d08 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Wed, 16 Jan 2013 03:30:04 -0300 Subject: [PATCH] ubb-patgen/ubb-patgen.c: new option -d to debounce the trigger --- ubb-patgen/Makefile | 2 +- ubb-patgen/README | 9 ++++- ubb-patgen/ubb-patgen.c | 76 +++++++++++++++++++++++++++++++++++------ 3 files changed, 74 insertions(+), 13 deletions(-) diff --git a/ubb-patgen/Makefile b/ubb-patgen/Makefile index 5bb248e..7450462 100644 --- a/ubb-patgen/Makefile +++ b/ubb-patgen/Makefile @@ -13,7 +13,7 @@ CC = mipsel-openwrt-linux-gcc CFLAGS = -g -Wall -O9 -I../libubb/include LDFLAGS = -LDLIBS = -L../libubb -lubb -lm +LDLIBS = -L../libubb -lubb -lm -lrt MAIN = ubb-patgen OBJS = ubb-patgen.o diff --git a/ubb-patgen/README b/ubb-patgen/README index 24ee456..692bd22 100644 --- a/ubb-patgen/README +++ b/ubb-patgen/README @@ -153,5 +153,12 @@ send the pattern immediately. Likewise, -t 1 waits for CLK to become 1. -t cannot be used with the -C option. -ubb-patgen usually starts the pattern about 2 us after the +ubb-patgen usually starts the pattern about 2-10 us after the trigger, but this can be delayed by other system activity. + +The trigger signal can be debounced with the option -d, e.g., + +# ubb-patgen -t 0 -d 100us 0f0 + +This accepts the trigger only after it has been zero for at least +100 microseconds. diff --git a/ubb-patgen/ubb-patgen.c b/ubb-patgen/ubb-patgen.c index e38c50b..06afbf6 100644 --- a/ubb-patgen/ubb-patgen.c +++ b/ubb-patgen/ubb-patgen.c @@ -323,8 +323,47 @@ static void wait_shifted(const struct mmcclk *clk) } +static void wait_trigger(int trigger, int debounce, + const struct timespec *debounce_ns) +{ + struct timespec end, now; + + /* + * @@@ could also try to use POSIX per-process timers here. May be + * slightly cleaner but could increase deviations. + */ + while (1) { + while (PIN(UBB_CLK) != trigger); + if (!debounce) + return; + if (clock_gettime(CLOCK_REALTIME, &end)) { + perror("clock_gettime"); + exit(1); + } + end.tv_sec += debounce_ns->tv_sec; + end.tv_nsec += debounce_ns->tv_nsec; + if (end.tv_nsec > 999999999) { + end.tv_nsec -= 1000000000; + end.tv_sec++; + } + while (PIN(UBB_CLK) == trigger) { + if (clock_gettime(CLOCK_REALTIME, &now)) { + perror("clock_gettime"); + exit(1); + } + if (now.tv_sec > end.tv_sec) + return; + if (now.tv_sec == end.tv_sec && + now.tv_nsec >= end.tv_nsec) + return; + } + } +} + + static void mmc_buffer(const struct mmcclk *clk, - uint8_t first, unsigned long buf, int nibbles, uint32_t mask, int trigger) + uint8_t first, unsigned long buf, int nibbles, uint32_t mask, + int trigger, int debounce, const struct timespec *debounce_ns) { /* * If under control of the MMC controller, DATx tri-state until we @@ -370,7 +409,7 @@ static void mmc_buffer(const struct mmcclk *clk, PDFUNS = mask; if (trigger != -1) - while (PIN(UBB_CLK) != trigger); + wait_trigger(trigger, debounce, debounce_ns); /* * Send the pattern with DMA. Note that we still have to send the first @@ -397,7 +436,8 @@ static void mmc_buffer(const struct mmcclk *clk, static void send_buffer(const struct mmcclk *clk, - const uint8_t *buf, int nibbles, uint32_t mask, int trigger) + const uint8_t *buf, int nibbles, uint32_t mask, + int trigger, int debounce, const struct timespec *debounce_ns) { unsigned long phys; @@ -407,12 +447,14 @@ static void send_buffer(const struct mmcclk *clk, } phys = physmem_xlat((void *) buf); - mmc_buffer(clk, buf[0] >> 4, phys, nibbles, mask, trigger); + mmc_buffer(clk, buf[0] >> 4, phys, nibbles, mask, + trigger, debounce, debounce_ns); } static void dma_pattern(const struct mmcclk *clk, - const char *pattern, uint32_t mask, int trigger) + const char *pattern, uint32_t mask, int trigger, + int debounce, const struct timespec *debounce_ns) { const uint8_t *buf; int n; @@ -442,7 +484,7 @@ static void dma_pattern(const struct mmcclk *clk, PDDATS = (buf[0] >> 4) << 10; PDDIRS = mask; - send_buffer(clk, buf, n, mask, trigger); + send_buffer(clk, buf, n, mask, trigger, debounce, debounce_ns); /* Final static state: the last pattern. */ @@ -592,10 +634,11 @@ static void usage(const char *name) "usage: %s\n" " %s [-q] -f freq_hz|-i interval_s\n" " %s [-q] [-f freq_hz|-i interval_s] -c [active_s]\n" -" %s [-q] [-f freq_hz|-i interval_s] [-C|-t 0|1] [-m mask] [-p]\n" -" file|pattern\n\n" +" %s [-q] [-f freq_hz|-i interval_s] [-C|-t 0|1 [-d debounce_s]]\n" +" [-m mask] [-p] file|pattern\n\n" " -c output bus clock on CLK without sending a pattern\n" " -C temporarily output bus clock on CLK (for debugging)\n" +" -d deb_s trigger debounce time (default: no debouncing)\n" " -f freq_hz set bus clock to the specified frequency (default: 1 MHz)\n" " -i inter_s set bus clock such that one cycle equals the specified " "interval\n" @@ -630,15 +673,17 @@ int main(int argc, char **argv) const char *pattern = NULL; int quiet = 0, force_pattern = 0; struct timespec active_ns; - int active_rel = 0; + int active_rel; int keep_clk = 1; uint8_t mask = 0xf; int trigger = -1; + struct timespec debounce_ns; + int debounce = 0, debounce_rel; char *end; int c; unsigned long tmp; - while ((c = getopt(argc, argv, "cCf:i:m:pqt:")) != EOF) + while ((c = getopt(argc, argv, "cCd:f:i:m:pqt:")) != EOF) switch (c) { case 'f': if (!frequency(optarg, &bus_hz, &bus_rel)) @@ -654,6 +699,14 @@ int main(int argc, char **argv) case 'C': clkout = 1; break; + case 'd': + if (!duration_timespec(optarg, + &debounce_ns, &debounce_rel)) + usage(*argv); + if (debounce_rel < 0) + usage(*argv); + debounce = 1; + break; case 'm': tmp = strtoul(optarg, &end, 0); if (*end) @@ -744,7 +797,8 @@ int main(int argc, char **argv) mmcclk_start(&clk); if (pattern) - dma_pattern(&clk, pattern, mask << 10, trigger); + dma_pattern(&clk, pattern, mask << 10, + trigger, debounce, &debounce_ns); if (!keep_clk) if (nanosleep(&active_ns, NULL))