From nobody Thu Jan 26 04:04:51 2023 X-Original-To: freebsd-arm@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4P2RtZ2F2Vz3bKWh for ; Thu, 26 Jan 2023 04:04:54 +0000 (UTC) (envelope-from 01070185ec3ff177-a3ef6a92-17ae-4b94-819b-c86b90ebb681-000000@eu-central-1.amazonses.com) Received: from b224-8.smtp-out.eu-central-1.amazonses.com (b224-8.smtp-out.eu-central-1.amazonses.com [69.169.224.8]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4P2RtY6Xbnz3Pk0 for ; Thu, 26 Jan 2023 04:04:53 +0000 (UTC) (envelope-from 01070185ec3ff177-a3ef6a92-17ae-4b94-819b-c86b90ebb681-000000@eu-central-1.amazonses.com) Authentication-Results: mx1.freebsd.org; none DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=ez3m2wtglgbm5wj4q3hdyvc7qtjtqmlb; d=cyclaero.com; t=1674705892; h=Content-Type:Mime-Version:Subject:From:In-Reply-To:Date:Cc:Content-Transfer-Encoding:Message-Id:References:To; bh=jlV5/TIfPy1vhrWrJHEPX1s5s71YpDZEM1tWFQpyxP4=; b=ETPVhFSmthK6uspsHHvf3QtIRrDalcCkPF2IVKiNaCoRLvyIRigc1fHskReSnXSW F6YK91BhjUBnHXhdfAoP1DtTwq3FtuSfpZ7gkEIUSTDcACFZFgAwgYa0PM4dgEoHicQ Xi9fEBGbobV1J8cQaHTh1Cn7G1ki01XfHhILod5qPV37ty6LEGdGue+Fxq7z3XuzRe8 l+YZKDXXCb1P0cNo2KpuFJpe7XAT/rrCnIudbVeCKj5lI/MQ9RDmXZkNbykldOzlpxg a6I0h15v9643M5Wuy11clFkFz4p2GKdKlqfQoVjNU/TFfaXU1+2qjW0RCEvURtErkpe qf6DcFEedg== DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=sokbgaaqhfgd6qjht2wmdajpuuanpimv; d=amazonses.com; t=1674705892; h=Content-Type:Mime-Version:Subject:From:In-Reply-To:Date:Cc:Content-Transfer-Encoding:Message-Id:References:To:Feedback-ID; bh=jlV5/TIfPy1vhrWrJHEPX1s5s71YpDZEM1tWFQpyxP4=; b=b/s4pK456h+J5BMCQDbAP7DD1lnmsP6wPaocdIrHoQd4+P0JRbxG16GtHXx8d2AC XgBnu3f914UIsyODG2O7n759VT4QaVKPNbABiieKLbKBxkwlPUkZO5SUmAIOkamCRlA 2WEU81fNiOeGexJRaWZ9AQ5wHJY3PBc4DaW5TDvY= Content-Type: text/plain; charset=utf-8 List-Id: Porting FreeBSD to ARM processors List-Archive: https://lists.freebsd.org/archives/freebsd-arm List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-freebsd-arm@freebsd.org Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.15\)) Subject: Re: GPIO inputs on Pis? From: "Dr. Rolf Jansen" In-Reply-To: <1cd552a7-b015-c935-06fc-9f12e1b37daa@denninger.net> Date: Thu, 26 Jan 2023 04:04:51 +0000 Cc: Karl Denninger Content-Transfer-Encoding: quoted-printable Message-ID: <01070185ec3ff177-a3ef6a92-17ae-4b94-819b-c86b90ebb681-000000@eu-central-1.amazonses.com> References: <0b235f83-7cb3-1d14-7c64-aee7c1c0c23d@denninger.net> <01070185e46b1a6e-ee34b885-1215-45c7-ac18-83320c02cac2-000000@eu-central-1.amazonses.com> <01070185e4732fd8-c0bede0b-d9df-4557-a174-cb237fa4bfaf-000000@eu-central-1.amazonses.com> <01070185e534f221-14f362b5-2b96-43f0-b0b0-f496ad9994fe-000000@eu-central-1.amazonses.com> <1cd552a7-b015-c935-06fc-9f12e1b37daa@denninger.net> To: freebsd-arm X-Mailer: Apple Mail (2.3445.104.15) Feedback-ID: 1.eu-central-1.i3TZMOZE/rJo3HQG0qvfyolMxXljeCj2Qj8Jp3rxK3c=:AmazonSES X-SES-Outgoing: 2023.01.26-69.169.224.8 X-Rspamd-Queue-Id: 4P2RtY6Xbnz3Pk0 X-Spamd-Bar: ---- X-Spamd-Result: default: False [-4.00 / 15.00]; REPLY(-4.00)[]; ASN(0.00)[asn:16509, ipnet:69.169.224.0/23, country:US] X-Rspamd-Pre-Result: action=no action; module=replies; Message is reply to one we originated X-ThisMailContainsUnwantedMimeParts: N > Am 25.01.2023 um 13:45 schrieb Karl Denninger : >=20 > On 1/24/2023 14:15, Dr. Rolf Jansen wrote: >> Yes, and for this reason, this GPIO event code which was developed by = Christian Kr=C3=A4mer in the course of the GSoC-2018 and has been = submitted in 2020 by Ian Lepore to the freebsd tree is perfect. >>=20 >> Ian tested it with a 10 MHz sqaure wave on an imx6 (ARMv7, 1GHz) and = got an event every 10 =C2=B5s. That means the max. speed without event = losses would be 100 kHz. I did not do exact measurements, however, my = impression is that my RPi4B can do it a tad faster than my BeagleBone = Black. With the RPi4, I needed to improve the debouncing of the encoder = and the buttons, because it saw hundreds of bounces which the BBB = didn=E2=80=99t. However, it may also be, that the internal GPIO circuits = of the BBB have a different damping characteristic. >>=20 >> Anyway for my applications, 100 kHz way faster than what I need. >>=20 >> On my GitHub repository I placed another example on using the GPIO = events for the RPi: >>=20 >> https://github.com/cyclaero/shutdd >>=20 >> See also the respective thread on this mailing list: >>=20 >> https://lists.freebsd.org/archives/freebsd-arm/2022-July/001576.html > So..... just to see if I'm understanding this correctly (pretty sure = I am having read through the test code). >=20 > Presume I have "X" pins configured as inputs and "Y" configured as = outputs. I use the ioctl calls to set the outputs (which works just = fine) and can read current input state (which also works.) >=20 > If I set on the same descriptor (not on the specific pins; it applies = to all input pins on that descriptor as it appears there's no = pin-specific setting in the configuration flags to enable this on a = pin-by-pin basis) the event report config type I want I can then = select() on the descriptor with the usual timeouts (or zero for a poll) = and get a "ready" (much as one would for any other sort of I/O) and, if = I do get a "ready" return on the descriptor a read() on that descriptor = will return zero or more structures of the type I said I configured, = each of which describes either an individual state change on one of = configured input pins that is set up for individual event reporting OR a = structure of the summary of changes for a given pin. >=20 My understanding of what you wrote above sounds correct. However, I = don=E2=80=99t use select(), since I am very comfortable with calling a = blocking read() from a loop in a pthread. The advantage with this is, = that there is almost no time gap in the user land between reading of the = events. Below comes an example You open the respective GPIO bank (the RPI4 got only 1 while the BBB got = 4) for reading. gpio_handle_t gpio0; if ((gpio0 =3D gpio_open(0)) !=3D GPIO_INVALID_HANDLE) { You configure the pins, here for a mechanical rotary encoder having a = push button facility on the axis. The clock and the button changes shall = cause interrupts, while the direction shall be polled.=20 gpio_config_t gcfg =3D {0, {}, 0, = GPIO_PIN_INPUT|GPIO_INTR_EDGE_FALLING}; // Encoder CLOCK gcfg.g_pin =3D 20; gpio_pin_set_flags(gpio0, &gcfg); // Encoder BUTTON gcfg.g_pin =3D 26; gpio_pin_set_flags(gpio0, &gcfg); // Encoder DIRECTION gcfg.g_pin =3D 19; gcfg.g_flags =3D GPIO_PIN_INPUT|GPIO_INTR_NONE; gpio_pin_set_flags(gpio0, &gcfg); Now the event loop: ssize_t n, rc, rs =3D sizeof(struct gpio_event_detail); double t; int c =3D 0; struct gpio_event_detail buffer[64]; do { if ((rc =3D read(gpio0, buffer, sizeof(buffer))) < 0) err(EXIT_FAILURE, "Cannot read from GPIO0"); if (rc%rs !=3D 0) err(EXIT_FAILURE, "%s: read() the odd count of %zd bytes = from GPIO0\n", getprogname(), rc); else { n =3D rc/rs - 1; t =3D nanostamp(buffer[n].gp_time); switch (buffer[n].gp_pin) { case 20: c +=3D (gpio_pin_get(gpio0, 19)) ? +1 : -1; break; case 19: break; case 26: default: break; } printf("%5d %12.9f\tGPIO0.%u \t%u\t%zd\n", c, t, = buffer[n].gp_pin, buffer[n].gp_pinstate, n); } } while (buffer[n].gp_pin !=3D 26); } Basically, that=E2=80=99s it. =20 > I assume given the 16-bit "count" field on the summary return that = counts are "since last returned" and not "since boot" or "since = descriptor was opened and configuration set.=E2=80=9C >=20 > This also presumes that there is some buffer depth on this that, at = some point, may be exceeded so if I "go away" for too long I may miss = things -- particularly if I need detail-level reporting. Yes, and for this reason I like to call blocking reads from within a = relatively tight event loop. > Thus it looks like that its possible for most cases (assuming = resolution of the time stamps is high enough and the driver timing is = accurate enough, plus the code is sparse enough that actually does the = reading) to not just read an optical encoder with this but also (if you = use detail reporting) to read a bi-phase encoder so you can determine = which direction it is moving. The computational resolution is nanoseconds, but of course you won=E2=80=99= t see interrupts in GHz speed - on a RPI4 expect some hundred kHz. I use = the following function for conversion to a double value: static inline double nanostamp(int64_t stamp) { uint64_t ns =3D (1000000000*(stamp & 0xFFFFFFFFu) >> 32); return (int32_t)(stamp >> 32) + ns*1e-9; } > On to check it out; if I missed something here a "heh idiot, no it = actually works like this!" would be appreciated :-) I do poll the direction pin when the clock pin of the encoder cause = interrupts. At least for mechanical encoders this is less cumbersome = because depending on the debouncing circuit you might see pulse trains = for each tick and tack. With respect to the direction it is then hard to = figure out whether it is actually 0 or 1.