Taste löst Interrupt am GPIO des RPI aus!

Für Fragen von Einsteigern und Programmieranfängern...
hpt
Beiträge: 48
Registriert: Sa 26. Jul 2014, 18:45
OS, Lazarus, FPC: Lazarus
CPU-Target: 32Bit

Taste löst Interrupt am GPIO des RPI aus!

Beitrag von hpt »

Wer hat einen funktionierenden Code-Schnipsel, welcher aufgrund eines Tastendrucks einen Interrupt am RaspberrryPi -GPIO auslöst und das auch noch softwaremäßig Tastenentprellt? Geht das auch für mehrere Tasten? Habe im www nichts passendes für Lazarus gefunden. Für Studienzwecke wäre auch eine Dokumentation (Kurzbeschreibung) sehr hilfreich. Ich würde mich über Eure Hilfe sehr freuen.
Danke - Schönen Abend!

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von Socke »

hpt hat geschrieben:Wer hat einen funktionierenden Code-Schnipsel, welcher aufgrund eines Tastendrucks einen Interrupt am RaspberrryPi -GPIO auslöst und das auch noch softwaremäßig Tastenentprellt? Geht das auch für mehrere Tasten? Habe im www nichts passendes für Lazarus gefunden.
Schau mal in pascalio nach: https://github.com/SAmeis/pascalio/blob ... fpgpio.pas

Der Code müsste in etwa so aussehen:

Code: Alles auswählen

var
  i: TGpioLinuxPin;
begin
  i := TGpioLInuxPin.Create(5);
  i.Direction := gdIn; // Richtung festlegen
  i.InterruptMode := [gimRising, gimFalling]; // bei steigender und fallender Flanke einen Interrupt auslösen (Taster drücken und loslassen)
  if i.WaitForInterrupt(-1) then  // auf Interrupts warten
    Writeln('Interrupt');
  else
    Writeln('Timeout');
end;
Wenn du in deinem Programm auf mehrere Schalter wartest, musst du für jeden Schalter einen Thread aufmachen und auf diesen warten. Gerne darfst du mir auch einen Patch zusenden, mit dem man auf mehrere Schalter warten kann ;-) Ebenso wäre eine Komponente sinnvoll, die das ganze für GUI-Anwendungen bereit stellt ...

Edit: eine Dokumentation für pascalio ist ebenfalls verfügbar.
Edit2: Im Beispiel oben muss der timeout ungleich 0 sein (<0 => unendliches Warten auf Interrupt, 0 => kein Warten, >0 => warten auf Interrupt oder timeout). Weiterhin wurde die Methode selbst korrigiert (siehe Github), sodass sie jetzt zuverlässig funktioniert.
Zuletzt geändert von Socke am Do 30. Okt 2014, 20:31, insgesamt 2-mal geändert.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

hpt
Beiträge: 48
Registriert: Sa 26. Jul 2014, 18:45
OS, Lazarus, FPC: Lazarus
CPU-Target: 32Bit

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von hpt »

Ganz lieben Dank an Socke, für die schnelle Stellungnahme. Habe natürlich sofort probieren müssen und eine Minimal-Anwendung geschrieben, in der ich auf Kopfdruck in einem Gui-Fenster die Interruptroutine wie vorgeschlagen eingesetzt habe.

Code: Alles auswählen

procedure TForm1.Button2Click(Sender: TObject);
begin
  i := TGpioLInuxPin.Create(5);
  i.Direction := gdIn; // Richtung festlegen
  i.InterruptMode := [gimRising, gimFalling]; 
  if i.WaitForInterrupt(0) then  // auf Interrupts warten
    Label1.caption:='Interrupt'
  else
    Label1.caption:='Timeout';
end;
Drückt man Button2, kommt ein Fenster mit der Fehlermeldung:
Unable to open file „/sys/class/gpio/edge“.

Ich habe mit dem Filemanger nachgesehen und gesehen, dass „edge“ im Verzeichnis /sys/class/gpio/gpio5/ steht !!! Also eine Ebene drunter...kann also irgendwie nicht stimmen.

Außerdem ist mir noch nicht klar, wie ich eine Int-Service-Routine aufrufen kann und in dieser den Interrupt sperren kann, damit er kein weiteres mal in dieser Zeit ausgelöst werden kann.

Ebenso frage ich mich, ob bei jedem Eingangspin der Interrupt (0) ausgelöst wird, denn dann müßte ich danach ja in der Service-Routine abfragen, welcher Taster (wenn es mehrere sind) gedrückt wurde.

Es ist interessant, dass man im Internet wenig bis gar nix (für Lazarus) über Interrupt Behandlung zu lesen ist. Wäre aber ein interessantes Gebiet zum Basteln und probieren – gerade beim Rpi! Jedenfalls freue ich mich schon auf die nächsten Tipps - danke danke danke !
Zuletzt geändert von Lori am So 26. Okt 2014, 13:11, insgesamt 1-mal geändert.
Grund: Highlighter

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von Socke »

hpt hat geschrieben:Drückt man Button2, kommt ein Fenster mit der Fehlermeldung:
Unable to open file „/sys/class/gpio/edge“.

Ich habe mit dem Filemanger nachgesehen und gesehen, dass „edge“ im Verzeichnis /sys/class/gpio/gpio5/ steht !!! Also eine Ebene drunter...kann also irgendwie nicht stimmen.
Das war ein Fehler; den gibt es jetzt nicht mehr.
hpt hat geschrieben:Außerdem ist mir noch nicht klar, wie ich eine Int-Service-Routine aufrufen kann und in dieser den Interrupt sperren kann, damit er kein weiteres mal in dieser Zeit ausgelöst werden kann.
An die echten Interrupts kommst du nur im Linux-Kernel heran. Da wir hier aber an sogenannten User-Space-Programmen arbeiten, können wir nur auf einen Interrupt warten - das heißt: dein Programm kann in dieser Zeit keine anderen Aktivitäten erledigen. Für den Benutzer sieht das so aus, als ob dein Programm sich aufgehangen hat.

Daraus folgt auch: solange dein Programm nach einen Interrupt nicht wieder erneut auf einen Interrupt wartet, merkt es nichts von einem erneutem Interrupt. Das hängt natürlich stark davon ab, wie und in welchen Zeitabständen auf Interrupts gewartet wird.

Falls du dennoch eine explizite Verhinderung benötigt, gelten die gleichen Möglichkeiten wie in Multi-Thread-Anwendungen; eine Möglichkeit wäre

Code: Alles auswählen

procedure Interrupt(pin: Integer);
const // InProc hat für alle Prozedur-Aufrufe den selben Speicherbereich
  InProc: Longint = 0;
begin
  // Falls InProc = 0 ist, diesen auf 1 setzen; Rückgabewert ist der alte Wert von InProc
  if InterlockedCompareExchange(InProc, 1, 0) = 0 then
  begin
    // Interrupt handler
  end;
  InProc := 0;  // für neuen Aufruf frei machen
end;
hpt hat geschrieben:Ebenso frage ich mich, ob bei jedem Eingangspin der Interrupt (0) ausgelöst wird, denn dann müßte ich danach ja in der Service-Routine abfragen, welcher Taster (wenn es mehrere sind) gedrückt wurde.
Wenn du für jeden Schalter einen Thread erstellst und in diesem Thread auf den Interrupt wartest, weißt du, welcher Schalter gedrückt wurde. Andernfalls: ja. Der Baustein MCP23017 bzw. MCP23S17 hat ein Register, in dem gespeichert wird, welche Eingangsleitung sich seit der letzten Abfrage geändert hat; damit kann man den Schalter auch noch viel später ermitteln (wenn der Schalter längst nicht mehr gedrückt ist) - aber das ist ein anderes Thema.
hpt hat geschrieben:Es ist interessant, dass man im Internet wenig bis gar nix (für Lazarus) über Interrupt Behandlung zu lesen ist. Wäre aber ein interessantes Gebiet zum Basteln und probieren – gerade beim Rpi! Jedenfalls freue ich mich schon auf die nächsten Tipps - danke danke danke !
Lazarus ist leider nicht ganz so populär, wie man sich das wünschen könnte; Falls du ein wenig von der Programmiersprache C verstehst, kannst du auch danach suchen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

hpt
Beiträge: 48
Registriert: Sa 26. Jul 2014, 18:45
OS, Lazarus, FPC: Lazarus
CPU-Target: 32Bit

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von hpt »

....Das war ein Fehler; den gibt es jetzt nicht mehr. !??
Wie was wo .....

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von Socke »

hpt hat geschrieben:....Das war ein Fehler; den gibt es jetzt nicht mehr. !??
Wie was wo .....
Ich habe ihn korrigiert und die Aktualisierung zu Github hochgeladen. Wenn du die Bibliothek erneut herunterlädst, hast du auch die Korrektur.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

hpt
Beiträge: 48
Registriert: Sa 26. Jul 2014, 18:45
OS, Lazarus, FPC: Lazarus
CPU-Target: 32Bit

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von hpt »

Habe die Version SAmeis-pascalio-f0c5698 downgeladen, davon im Verzeichnis src/die fpgpio.
Meine Application legt wohl das Verzeichnis /sys/class/gpio/gpio5/ an, aber versucht scheinbar auf /sys/class/gpio/ zu lesen....
Jedenfalls kommt nach wie vor der Fehler: Unable to open file „/sys/class/gpio/edge“
Mache ich was falsch?! Schönen Tag wünscht HPT

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von Socke »

Du hast alles richtig gemacht.
Den gleichen Fehler gab es ein paar Zeilen weiter noch einmal (beim Lesen statt Schreiben). In commit 1c77bd7 ist der Fehler behoben.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von mschnell »

Socke hat geschrieben:An die echten Interrupts kommst du nur im Linux-Kernel heran. Da wir hier aber an sogenannten User-Space-Programmen arbeiten, können wir nur auf einen Interrupt warten - das heißt: dein Programm kann in dieser Zeit keine anderen Aktivitäten erledigen. Für den Benutzer sieht das so aus, als ob dein Programm sich aufgehangen hat.
Dafür gibt es doch Threads. Wenn das Warten auf den Interrupt durch ein Blocking Read auf ein Device-File ( „/sys/class/gpio/gpio5/edge“) gemacht wird bleibt der (Worker-) Thread an dieser Stelle stehen, aber der Main-Thread mit der GUI läuft weiter.

Oder ist das bei den "User Space Interrupts" anders ?

-Michael

hpt
Beiträge: 48
Registriert: Sa 26. Jul 2014, 18:45
OS, Lazarus, FPC: Lazarus
CPU-Target: 32Bit

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von hpt »

schönen Nachmittag
jedenfalls will es bei mir nicht funktionieren.
Ich habe jetzt einiges probiert, aber wenn ich button2 drücke, kommt nur "Interrupt" aber sonst nichts mehr....
Keine Reaktion des Tasters, welcher hardwaremäßig an Pin18 (12 von der Steckleiste) über einen Pull-up an 3,3Vliegt. D.h. ich habe im Ruhezustand log1 und wenn ich den Taster drücke, log 0. Deshalb habe ich auch die Folge in der Anweisung umgedreht also "i.InterruptMode := [gimFalling, gimRising]; oder auch nur gimFalling.
Hat aber alles nichts gebracht. Was könnte ich weiter ausprobieren?

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von Socke »

Hallo,

ich muss zugeben, die Interrupts sind noch nicht ausführlich getestet. Dabei muss ich zugeben, dass es mir leider noch nicht gelungen ist, voll funktionsfähig in Pascal umzusetzen.

Der folgende Code ist mehr oder weniger eine Übersetzung eines C-Programms nach Free Pascal. Das Original ist zu finden unter: http://elinux.org/GPIO#Using_poll.28.29 ... O_0_change
Das C-Programm (herunterladen in eine Datei gpio-int-test.c; kopilieren mit gcc gpio-int-test.c -o gpio-int-test; ausführen z.B. mit sudo ./gpio-int-test 25) funktioniert halbwegs.

Edit: Die Pascal-Variante funktioniert jetzt! In der Ursprünglichen Version wurde nach /sys/class/gpio/gpio<nr>/edge die Nummer des GPIO-Pins (Variable buf) geschrieben - was natürlich nicht funktionieren konnte. Jetzt wird korrekter Weise der Edge-String geschrieben.

Code: Alles auswählen

(* Copyright (c) 2011, RidgeRun
 * Source: http://elinux.org/GPIO#Using_poll.28.29_to_monitor_for_GPIO_0_change
 *
 * Pascal Port: 2014, Simon Ameis <simon.ameis@web.de>
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the RidgeRun.
 * 4. Neither the name of the RidgeRun nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *)
program gpio_int_test;
 
{$mode objfpc}{$H+}
 
uses
  baseunix, unix, ctypes;
 
const
  clib = 'c';
// libc function headers
// avoid dependency on UNIT libc; it is available only on i386
function fflush(__stream:cint):longint;cdecl;external clib name 'fflush';
procedure perror(__s:Pchar);cdecl;external clib name 'perror';
function atoi(__nptr:Pchar):longint;cdecl;external clib name 'atoi';
 
(*****************************************************************
 * Constants
 ****************************************************************)
const
  SYSFS_GPIO_DIR = '/sys/class/gpio';
  POLL_TIMEOUT = (3 * 1000); // 3 seconds
  MAX_BUF = 64;
 
 
 
(****************************************************************
 * gpio_export
 ****************************************************************)
function gpio_export(gpio: cuint): cint;
var
  fd: cint;
  buf: Ansistring;
begin
  fd := fpOpen(SYSFS_GPIO_DIR + '/export', O_WRONLY);
  if (fd < 0) then
  begin
    perror('gpio/export');
    exit(fd);
  end;
  str(gpio, buf);
  fpWrite(fd, Pchar(buf), Length(buf));
  fpClose(fd);
  exit(0);
end;
 
(****************************************************************
 * gpio_unexport
 ****************************************************************)
function gpio_unexport(gpio: cuint): cint;
var
  fd: cint;
  buf: Ansistring;
begin
  fd := fpOpen(SYSFS_GPIO_DIR + '/unexport', O_WRONLY);
  if (fd < 0) then
  begin
    perror('gpio/export');
    exit(fd);
  end;
  str(gpio, buf);
  fpWrite(fd, PChar(buf), Length(buf));
  fpClose(fd);
  exit(0);
end;
 
(****************************************************************
 * gpio_set_dir
 ****************************************************************)
function gpio_set_dir(gpio: cuint; out_flag: Boolean): cint;
var
  fd: cint;
  buf: Ansistring;
begin
  str(gpio, buf);
  buf := SYSFS_GPIO_DIR + '/gpio' + buf + '/direction';
 
  fd := fpOpen(buf, O_WRONLY);
  if (fd < 0) then
  begin
    perror('gpio/direction');
    exit(fd);
  end;
 
  if (out_flag) then
    fpWrite(fd, 'out', 3)
  else
    fpWrite(fd, 'in', 2);
 
  fpClose(fd);
  exit(0);
end;
 
(****************************************************************
 * gpio_set_value
 ****************************************************************)
function gpio_set_value(gpio: cuint; value: Boolean): cint;
var
  fd: cint;
  buf: Ansistring;
begin
  str(gpio, buf);
  buf := SYSFS_GPIO_DIR + '/gpio' + buf + '/value';
 
  fd := fpOpen(buf, O_WRONLY);
  if (fd < 0) then
  begin
    perror('gpio/set-value');
    exit(fd);
  end;
 
  if (value) then
    fpWrite(fd, PChar('1'), 1)
  else
    fpWrite(fd, PChar('0'), 1);
 
  fpClose(fd);
  exit(0);
end;
 
(****************************************************************
 * gpio_get_value
 ****************************************************************)
function gpio_get_value(gpio: cuint; var value: Boolean): cint;
var
  fd: cint;
  buf: Ansistring;
  ch: Char;
begin
  str(gpio, buf);
  buf := SYSFS_GPIO_DIR + '/gpio' + buf + '/value';
 
  fd := FpOpen(buf, O_RDONLY);
  if (fd < 0) then
  begin
    perror('gpio/get-value');
    exit(fd);
  end;
 
  fpRead(fd, @ch, 1);
 
  value := (ch <> '0');
 
  fpClose(fd);
  exit(0);
end;
 
(****************************************************************
 * gpio_set_edge
 ****************************************************************)
function gpio_set_edge(gpio: cuint; edge: Ansistring): cuint;
var
  fd: cint;
  buf: Ansistring;
begin
  str(gpio, buf);
  buf := SYSFS_GPIO_DIR + '/gpio' + buf + '/edge';
 
  fd := FpOpen(buf, O_WRONLY);
  if (fd < 0) then
  begin
    perror('gpio/set-edge');
    exit(fd);
  end;
 
  fpWrite(fd, PChar(edge), length(edge));
  fpClose(fd);
  exit(0);
end;
 
(****************************************************************
 * gpio_fd_open
 ****************************************************************)
function gpio_fd_open(gpio: cuint): cint;
var
  fd: cint;
  buf: Ansistring;
begin
  str(gpio, buf);
  buf := SYSFS_GPIO_DIR + '/gpio' + buf + '/value';
 
  fd := FpOpen(buf, O_RDONLY or O_NONBLOCK);
  if (fd < 0) then
  begin
    perror('gpio/fd_open');
  end;
  exit(fd);
end;
 
(****************************************************************
 * gpio_fd_close
 ****************************************************************)
 
function gpio_fd_close(fd: cint): cint;
begin
	Result := fpClose(fd);
end;
 
(****************************************************************
 * Main
 ****************************************************************)
function main(argc: cint; argv: PPChar; envp: PPChar): cint;
var
  fdset: Array[0..1] of pollfd;
  nfds: cint;
  gpio_fd, timeout, rc: cint;
  len: TSize;
  buf: String[MAX_BUF];
  gpio: cint;
  value: Boolean;
begin
  nfds := 2;
 
  if (argc < 2) then
  begin
    WriteLn('Usage: gpio_int_test <gpio-pin>', LineEnding);
    WriteLn('Waits for a change in the GPIO pin voltage level or input on stdin.');
    Writeln('Author: RidgeRun - Pascal Port: Simon Ameis');
    exit(-1);
  end;
 
  gpio := atoi(argv[1]);
  gpio_export(gpio);
  gpio_set_dir(gpio, False);
  gpio_set_edge(gpio, 'rising');
  gpio_fd := gpio_fd_open(gpio);
 
  timeout := POLL_TIMEOUT;
  while True do
  begin
    FillByte(fdset, SizeOf(fdset), 0);
 
    fdset[0].fd := StdInputHandle;
    fdset[0].events := POLLIN;
 
    fdset[1].fd := gpio_fd;
    fdset[1].events := POLLPRI;
 
    rc := fpPoll(@fdset[0], nfds, timeout);
    if (rc < 0) then
    begin
      Writeln(ErrOutput, LineEnding, 'poll() failed.');
      exit(-1);
    end else
    if (rc = 0) then
    begin
      write('.');
    end;
 
    if(fdset[1].revents and POLLPRI) <> 0 then
    begin
      len := FpRead(fdset[1].fd, @buf[1], MAX_BUF);
      gpio_get_value(gpio, value);
      writeln(LineEnding, 'poll() GPIO ', gpio, ' interrupt occured; value: ', value);
    end;
 
    if (fdset[0].revents AND POLLIN) <> 0 then
    begin
      FpRead(fdset[0].fd, @buf[1], 1);
      writeln(LineEnding, 'poll() stdin read ', buf[1]);
    end;
    fflush(StdInputHandle);
  end;
 
  gpio_fd_close(gpio_fd);
  exit(0);
end;
 
 
begin
  ExitCode := main(argc, argv, envp);
end.
Zum Entprellen kann dir Wikipedia weiterhelfen: https://de.wikipedia.org/wiki/Prellen
Zuletzt geändert von Socke am Mo 27. Okt 2014, 21:28, insgesamt 2-mal geändert.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von mschnell »

Blockiert "gpio_get_value" bis zur nächsten Änderung ?

Wenn ja: Um eine GUI am Laufen zu halten darf man es nur in einem Worker Thread aufrufen.

Wenn nein: wie kann man die nächste Änderung (die Original-Frage ging um "Interrupt") erkennen, ohne ein "Busy-Pollen" zu veranstalten ? (Auch hier braucht man vermutlich einen Worker-Thread, der den Interrupt an die GUI mit "Synchrionize", "Queue" oder "QueueAsyncCall" signalisiert.)

-Michael

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von Socke »

mschnell hat geschrieben:Blockiert "gpio_get_value" bis zur nächsten Änderung ?
Nein gpio_get_value liest nur den aktuellen Wert (der sich theoretisch zwischen Interrupt und Lesen ändern kann). Der Systemcall fpPoll blockiert bis zu einem Interrupt bzw. bis zu einem Timeout.

Mit dem Code wollte ich das generelle Vorgehen verdeutlichen: zuerst suche ich nach C-Programme und übersetze diese nach Pascal; dann wird der Code in PascalIO integriert. Da meine Pascal-Variante noch nicht zuverlässig funktioniert, bin ich über Fehlerhinweise dankbar.

Das Blocking-Problem habe ich bisher ausgelassen; als Lösung hatte ich da ein paar Komponenten im Sinn, die das ganze Threading und Synchronisation kapseln. Die zu implementieren hat für mich noch keinen Sinn, solange die Grundlagen noch nicht funktionieren.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von mschnell »

Socke hat geschrieben:Das Blocking-Problem habe ich bisher ausgelassen; als Lösung hatte ich da ein paar Komponenten im Sinn, die das ganze Threading und Synchronisation kapseln.
Genau !
Ein Beispiel wie sowas gut gemacht werden kann ist AsyncPro (was es aber bis jetzt nur für Delphi/Windows gibt): Intern wird (z.B. zu Empfang asynchroner Daten) ein Thread aufgesetzt. Die Klasse stellt aber Main-Thread-Events zur Verfügung, in denen man die Bearbeitungs-Funktionen angibt, die dann ganz normal im GUI-Thread der Applikation laufen. Der Anwender merkt von den Threads nichts, bekommt aber Events als "Interrupt", so wie der OP sich das vermutlich vorstellt.

-Michael

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Taste löst Interrupt am GPIO des RPI aus!

Beitrag von Socke »

mschnell hat geschrieben:Ein Beispiel wie sowas gut gemacht werden kann ist AsyncPro (was es aber bis jetzt nur für Delphi/Windows gibt): Intern wird (z.B. zu Empfang asynchroner Daten) ein Thread aufgesetzt. Die Klasse stellt aber Main-Thread-Events zur Verfügung, in denen man die Bearbeitungs-Funktionen angibt, die dann ganz normal im GUI-Thread der Applikation laufen. Der Anwender merkt von den Threads nichts, bekommt aber Events als "Interrupt", so wie der OP sich das vermutlich vorstellt.
TThread.Synchronize() arbeitet auschließlich mit einem einzigen Thread (dem Mainthread in Lazarus-Anwendungen). Da ich in eingebettenen Systemen viel eher eine N-zu-N-Kommunikation zwischen den Threads bevorzuge, hatte ich das noch nicht implementiert.

Vielleicht kannst du mal einen Blick auf den Quelltext oben werfen und nach Fehlern suchen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten