C/C++ GPIO lib: pigpio oder WiringPi?

  • ok, danke, ich lass es mal auf mich zukommen....
    notfalls vielleicht wirklich irgendwann mal ein Raspi 2.0, nach den ersten Tests.

    Nachdem aber dann wohl zumindest das Linux an sich schon ein ziemlicher Flaschenhals fürs Timing-Verhalten zu sein scheint (alle 200µs ein paar Pins abfragen) - ist das dann mit pigpio vs. wiringPi etwas zusätzlich sehr zeitkritisches oder sind dann beide in diesem "Gesamtrahmen" eher gleich? (low level-Pin-Abfragen sind mir zumindest im Moment noch zu kyptisch)

    Einmal editiert, zuletzt von HaWe (16. Oktober 2015 um 17:17)

  • Also ich würde dazu tendieren, die pigpio als vom Zeitverhalten besser als die wiringPi einzustufen.
    Das ist aber jetzt nur ein Bauchgefühl und ich kann das nicht stichhaltig belegen.
    Dazu müsste man sich mal ein paar Tests gönnen ... und das wird dann ohne Oszi m.E. mehr als schwierig ...

    cu,
    -ds-

  • danke für die Info, aber auf plus/minus 10µs kommts dann ja sicher nicht an, wenn 200µs schon das Problem sind.
    Einfache Syntax wäre dann eher das schlagende Argument, aber nicht nur für analog und digital-Pins, sondern auch für UART und i2c (was ja zumindest bei Wiring für Arduino mit drin ist).

    Einmal editiert, zuletzt von HaWe (16. Oktober 2015 um 17:32)


  • Nachdem aber dann wohl zumindest das Linux an sich schon ein ziemlicher Flaschenhals fürs Timing-Verhalten zu sein scheint (alle 200µs ein paar Pins abfragen)

    Hm, das ist so auch wieder nicht ganz richtig.

    Mit meinen Messungen habe ich r/w Zugriffsgeschwindigkeiten von 5-7MHz auf dem GPIO erreicht (mit Memorybarriers). Das wirst Du mit deinem Arduino wohl nicht schaffen. Allerdings kannnst Du das nicht dauerhaft sicherstellen! Wenn es für Deine Applikation hinreichend wäre, eine Messung durchzuführen, danach etwas (um eine Größenordnung anzugeben - 10ms) zu schlafen und danach wieder kurzzeitig (mit hoher Frequenz pollenderweise) zu messen, dann kommst Du in den Bereich des Möglichen - auch mit einem Linux Desktopkernel. Was Du allerdings in Deinem Algorithmus berücksichtigen mußt ist der Umstand, daß er damit klarkommt, jederzeit preempted zu werden. Bekommst Du das algortihmisch unter einen Hut, dann kannst Du durchaus von den vielen Vorteilen des Linux/der Hardware profitieren.

  • was heißt das jetzt für "12 dPins abfragen in 200µs-Takt-Cycles" hinsichtlich pigpio und WiringPi quantifiziert, in µs Unterschied?

    es laufen ständig sehr viele sehr lange Rechen-Tasks parallel, die manchmal einige Sekunden pro Rechenzyklus dauern, manchmal auch nur wenige Dutzend ms. Bei den langen könnte man aber durchaus zwischenzeitlich ein sleep einfügen, da low-priority.

    Einmal editiert, zuletzt von HaWe (16. Oktober 2015 um 17:44)

  • nein, das war ein Missverständnis , UART und i2c bezog sich nur auf die API, nicht auf das Timing.
    Aber auch die Anfänger-taugliche und "einfache" API war ja ein wichtiges Kriterium, zusätzlich zum Timing.

    Einmal editiert, zuletzt von HaWe (16. Oktober 2015 um 17:42)


  • was heißt das jetzt für "12 dPins abfragen in 200µs-Takt-Cycles" hinsichtlich pigpio und WiringPi quantifiziert, in µs Unterschied?


    Dein Problem wird nicht sein 12 pins inherhalb von 200µs abzufragen. Du kannst die Pins 1000mal abfragen in dieser Zeit. Dein Problem wird sein, equidistant innerhalb der 200µs immer wieder "dran sein zu können". Das erlaubt Dir der Scheduler nicht.

    Threadkontextwechsel sind teuer. Viel teurer, als ein einfaches Pushen von Registern auf den Stack und anschließendes neues Laden der alten Registerwerte (so wie beim Interrupt). Beim Threadwechsel muß der komplette Schedulercode durchlaufen werden und dieser muß feststellen, welcher der 300 Threads nun dran sein soll. Du konkurriest hier mit vielen anderen Threads im System und obendrein bewegst Du Dich unter der Gesetzgebung des Schedulingmodells. Da kommst Du nicht raus. Und wenn der Gesetzgeber sagt, daß Dein Thread jetzt nicht drankommt, weil er etwas anderes machen will, dann hast Du Pech ... und nix ist mit konstanten 200µs Takt.

  • das ist doch alles klar inzwischen, aber die Frage war doch:
    inwieweit wird das eh schon schwammige Linux-Verhalten signifikant schlechter von pigpio oder von WiringPi beeinflusst?
    pthread verwende ich ja schließlich ebenfalls in beiden Fällen.

    Einmal editiert, zuletzt von HaWe (16. Oktober 2015 um 17:54)


  • ...
    inwieweit wird das eh schon schwammige Linux-Verhalten signifikant schlechter von pigpio oder von WiringPi beeinflusst?
    ...


    das Verhalten von Linux beeinflusst Du in beiden Fällen nicht ... Linux beeinflusst das Verhalten der Libs, wobei ich mein Meinung ja schon kundgetan habe.
    Darüber eine konkrete Aussage zu machen würde imho bedeuten, hier eine Testreihe aufzusetzen und über mindestens zwei Kanäle mit einem Oszi die Reaktions- bzw. Auslösezeiten der beiden Libs zu protokollieren.
    Wobei das imho wiederum auch keine 100%ige Sicherheit bietet, da das Latenzverhalten des Kernels von Fall zu Fall, auch bei derselben Library, verschieden sein dürfte.

    Was die API betrifft, würde ich jetzt sagen, ist das reine Geschmackssache. Mir persönlich sind z.B. ioctl()-Aufrufe lieber, als systemcalls mit einer ellenlangen Parameter-Liste.
    Was Du beachten solltest ist, dass die wiringPi und die pgpio verschiedene Pin-Nummerierungen verwenden.

    cu,
    -ds-

  • Hm, wenn Du das Linux-Schedulerverhalten als schwammig bezeichnest, dann kann definitionsgemäß jedes Stück Code, welches das Betriebssystem benutzt die Schwammigkeit nur erhöhen. WiringPi verwendet z.B. einen Thread, um seine "Interrupts" zu realisieren. Nun kannst Du im Code nachschauen, und feststellen, daß die Prio zwar angehoben ist, der Thread jedoch kein RT Thread ist und Dir Deine Meinung bilden, ob das hinreichend ist oder nicht. Ich vermute damit ist die Trockenübung beendet und Du fängst einfach mal mit einer der o.g. Libraries an. Es ist schwer aus der Ferne zu beurteilen, welche Bibliotheksfunktionalität Du benötigst, wie Du Deinen Algorithmus strukturierst und welche harten Zeitanforderungen Du benötigst. Wenn Du z.B. I2C programmieren willst, dann kannst Du auch geradeheraus die C-runtimelib mit open, read, write und close verwenden. Die Adresse setzt Du per iocrtl und fertig. Ob das nun besser oder schlechter ist, als über eine der o.g. Lib's zu gehen, ist Geschmackssache. Ich glaube auch nicht, daß es das vordergründige Problem ist, die richtige Lib herausgezogen zu haben, sondern daß man seinen Algorithmus so aufstellt, daß er unter der "Gesetzgebung des Schedulers" immer (nicht nur meistens - weil meistens ist einfach :-)) die richtigen Ergebnisse liefert.

  • Also ich würde auch sagen ... nur weil möglicherweise die eine oder andere Funktion hin und wieder mit bis zu 1ms delay ausgeführt werden könnte, würde ich da jetzt auch keine Wissenschaft draus machen.
    Erst mal reinschnuppern, ausprobieren, bei Problemen die Lib oder gleich das OS wechseln.

    cu,
    -ds-

  • Was Du beachten solltest ist, dass die wiringPi und die pgpio verschiedene Pin-Nummerierungen verwenden.

    cu,
    -ds-

    das ist ja ein Ding!
    Danke, da wär ich so schnell nicht drauf gekommen!

    aber was das OS angeht: dass man keinen festen Timer-IRQs auf ARM-Prozessor-Ebene implementieren kann, jenseits von Linux-Tasks, hatte ich vorher auch nicht vermutet.

    Einmal editiert, zuletzt von HaWe (16. Oktober 2015 um 19:05)


  • ... dass man keinen festen Timer-IRQs auf ARM-Prozessor-Ebene implementieren kann ...


    na - wie schon gesagt, DMA-Takt ... aber da kommen wir auf eine Ebene, die ich mir noch nicht zu Gemüte geführt habe und wo ich ja schon sagte, dass Du Dir die passenden Anhaltspunkte evtl. aus der pigpio rausflöhen musst.

    cu,
    -ds-

  • ist dieser Realtime-Kernel oder auch der DMA-Takt etwas, was man ohne Weiteres (z.B. wie "attachInterrupt()" bei Arduino ) einfach zusätzlich zum Raspbian-basierten C-Code einfügen kann?
    Ich brauche es ja nur für 1 einzige Funktion im gesamten Programm - der Rest sollte schon weiterhin mit den üblichen Raspbian- g++ und POSIX pthread API-Funktionen programmierbar sein.

    Einmal editiert, zuletzt von HaWe (16. Oktober 2015 um 19:24)


  • ist dieser Realtime-Kernel oder auch der DMA-Takt etwas, was man ohne Weiteres (z.B. wie "attachInterrupt()" bei Arduino ) einfach zusätzlich zum Raspbian-basierten C-Code einfügen kann?
    Ich brauche es ja nur für 1 einzige Funktion im gesamten Programm - der Rest sollte schon weiterhin mit den üblichen Raspbian- g++ und POSIX pthread API-Funktionen programmierbar sein.

    Noe, so einfach wird's nicht werden - insbesondere wenn du wiringPI mit seinem eigenen Threading benutzt, musst du da schon genau drauf gucken, ob und wie sich das vertraegt.


    Wenn du auf diese Bibliotheken verzichtest (was nicht besonders schwer ist), dann kannst du das selbst bestimmen - ansonsten ist das alles C/C++, du musst dich halt an die Realtime-Regeln halten. ZB nicht wie bloede mit Speicher rumsauen.

  • ok, also erstmal testen, was das normale OS angeht. Vllt reicht es ja.
    Was pigpio und wiringPi angeht, lese ich da allerdings keine durchschlagenden Argumente für oder gegen das eine oder andere heraus, richtig?


    ps,
    OMG, was eine bekloppte GPIO-Nummerierung bei wiringPi und BCM! Wer denkt sich denn SO was aus?!

    gpio1.png

    Einmal editiert, zuletzt von HaWe (16. Oktober 2015 um 20:27)


  • Was pigpio und wiringPi angeht, lese ich da allerdings keine durchschlagenden Argumente für oder gegen das eine oder andere heraus, richtig?

    Nun, wenn Du Dich jetzt nicht entscheiden kannst, welche Lib Du nimmst, dann mach halt aus der Not eine Tugend und bau Dir einen kleinen Abstraktionslayer zwischen Deine App und die Libs. Dann kannst Du sie sogar gegeneinander testen. Aber wie gesagt - am "O-Kalkül" ändert das Null-Komma-Nix. Deine App muß mit dem Scheduler klarkommen, da hilft Dir keine Lib. Trau Dich jetzt mal einfach... :)

  • deswegen fragte hich hier ja nach Erfahrungen und Kritierien, die fürs eine oder andere sprechen, habe jetzt aber leider noch keine wirklich konkreten Unterschiede (Leistungsfähigkeit, Einfachheit, (fehlender) Funktionsumfang etc.) herauslesen können. Wenn beide grob das gleiche bieten, würde ich sonst eher zu wiringPi tendieren, wegen der Ähnlichkeit zu Arduino Sketch/Wiring, was mir ja schon recht vertraut ist.update:

    pwm an 2 pins getestet (wiringPins 0+1, BCM_GPIO 17+18) : funktioniert!

    update2:
    Habe jetzt in der WiringPi lib auch eine Funktion entdeckt für Pinchange-IRQs auf ARM-Prozessor-Ebene (!). Diese sind einfach zu implementieren. Außerdem nutzt wiringPi zusätzlich (für andere Dinge) auch pthread, ist also damit grundsätzlich kompatibel und hat sogar weitere vereinfachte API Funktionen dafür, wenn man das möchte.. Beides war ja wichtig, sowohl von der Performance als auch von der API syntax. i-Tüpfelchen ist noch die Serial-lib, die auch die UART-Verwendung deutlich vereinfacht. Damit steht mein Favorit jetzt eigentlich fest - danke für alle, die mitgeholfen haben!

    //Zusammengefügt von trek_star: Bitte gewöhne dir das Doppelposting ab. Das macht alles nur unübersichtlich.

    Einmal editiert, zuletzt von Alex (21. Oktober 2015 um 10:55)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!