Sign in Join
Wiki copytemporary

Revision 5 of 5, by Trev on 2-18-2020. The page as it is now.

Lazarus on Raspberry Pi/de

Lazarus on Raspbian Wheezy.

/File:Lazarus_on_Raspberry_Pi_Raspian_Wheezy_version_2012-10-28.png

Lazarus unter Raspbian Wheezy

Raspberry Pi Logo.png

Dieser Artikel behandelt ausschließlich Raspberry Pi.

Siehe auch: Multiplatform Programming Guide/de

Der Raspberry Pi ist ein kreditkartengroßer Einplatinenrechner. Er wurde in Großbritannien von der Raspberry Pi Foundation ursprünglich entwickelt, um den grundlegenden Informatikunterricht in Schulen zu fördern. Raspberry Pis können aber nicht nur für die Ausbildung, sondern für die unterschiedlichsten Zwecke, z. B. als Medienserver, Robotersteuerungen und für die Regelungstechnik eingesetzt werden.

Die Raspberry Pi Foundation empfiehlt als Standard-Betriebssystem Raspbian Wheezy. Alternative Betriebssysteme für den RPI sind z. B. RISC OS und verschiedene Linux-Distributionen, einschließlich Android.

Lazarus läuft nativ unter dem Betriebssystem Raspbian.

Installation 1

Installation 2

Installation 3

Installation 4

Raspberry Pi 2

Seit Juni 2015 funktioniert die oben angeführte "out of the box" Installationsmethode auch auf dem Raspberry Pi 2 Model B. Allerdings ist nach gegenwärtigem Stand die installierte Version recht alt. Wer die neuesten Versionen des Free Pascal Compilers und der Lazarus IDE installieren möchte, findet eine Anleitung in diesem Artikel.

Lazarus "out of the box" auf dem Raspberry Pi 2

Übersetzen aus den Quelltexten

Alternativ kann Lazarus auch aus den Subversion-Quelltexten übersetzt werden. Einzelheiten sind unter Michell Computing: Lazarus on the Raspberry Pi beschrieben.

Starten von Lazarus unter Raspbian Wheezy

Lazarus auf dem Raspberry Pi

Nummerierung der GPIO-Anschlüsse

Zugriff auf externe Hardware

Raspberry Pi pinout

/File:rpi_pinout_all_50.png

Belegung der externen Anschlüsse des Raspberry Pi

Eines der Ziele bei der Entwicklung des Raspberry Pi bestand darin, einfachen und schnellen Zugriff auf esterne Geräte wie Sensoren und Aktuatoren zu ermöglichen. Es gibt vier Möglichkeiten, die E/A-Optionen unter Lazarus und Free Pascal zu nutzen:

  1. Direktzugriff über die BaseUnix-Unit
  2. Zugriff über gekapselte Shell-Aufrufe
  3. Zugriff über die wiringPi library.
  4. Zugriff über die Unit rpi_hal> "Lazarus on Raspberry Pi/de").

1. Nativer Hardware-Zugriff

/File:testprogram_for_GPIO_on_RPI_annotated.png

Einfaches Testprogramm für den Zugriff auf den GPIO-Port des Raspberry Pi

/File:rpi_testcircuit_1d.png

Testschaltung für den GPIO-Zugriff mit dem beschriebenen Programm

/File:rpi_testcircuit_1p_annotaded.png

Einfache Demo-Umsetzung der Schaltung auf einer Steckplatine

Diese Methode bietet Zugriff auf externe Hardware, ohne zusätzliche Bibliotheken oder Packages zu benötigen. Die einzige Voraussetzung ist die BaseUnix-Bibliothek, die zur RTL gehört und mit Free Pascal automatisch mitinstalliert wird.

Schalten eines Gerätes über den GPIO-Port

Im folgenden Beispiel ist ein einfaches Programm aufgelistet, das den GPIO-Pin 17 als Ausgang zum Schalten einer LED, eines Transistors oder eines Relais benutzt. Es enthält eine ToggleBox mit dem Namen GPIO17ToggleBox und zur Aufzeichnung von Return-Codes ein TMemo-Feld mit der Bezeichnung LogMemo.

Hardwareseitig wurde die Anode einer LED mit Pin 11 des Anschlusses auf dem Pi (entsprechend GPIO-Pin 17 des BCM2835 SOC) und ihre Kathode über einen 68-Ohm-Schutzwiderstand mit Pin 6 des Pi-Anschlusses (GND = Masse) verbunden (s. auch die Beschreibung bei Upton and Halfacree). Damit kann die LED durch die ToggleBox des Programms ein- und ausgeschaltet werden.

Das Programm muss mit Root-Rechten ausgeführt werden, d. h. entweder von einem Root-Account aus (aus Sicherheitsgründen weniger zu empfehlen) oder über das Shell-Kommando su.

Steuerungs-Unit:

pascal
unit Unit1;
    
    {Demo application for GPIO on Raspberry Pi}
    {Inspired by the Python input/output demo application by Gareth Halfacree}
    {written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
    
    {$mode objfpc}{$H+}
    
    interface
    
    uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
      Unix, BaseUnix;
    
    type
    
      { TForm1 }
    
      TForm1 = class(TForm)
        LogMemo: TMemo;
        GPIO17ToggleBox: TToggleBox;
        procedure FormActivate(Sender: TObject);
        procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
        procedure GPIO17ToggleBoxChange(Sender: TObject);
      private
        { private declarations }
      public
        { public declarations }
      end;
    
    const
      PIN_17: PChar = '17';
      PIN_ON: PChar = '1';
      PIN_OFF: PChar = '0';
      OUT_DIRECTION: PChar = 'out';
    
    var
      Form1: TForm1;
      gReturnCode: longint; {stores the result of the IO operation}
    
    implementation
    
    {$R *.lfm}
    
    { TForm1 }
    
    procedure TForm1.FormActivate(Sender: TObject);
    var
      fileDesc: integer;
    begin
      { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
      try
        fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
        gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      finally
        gReturnCode := fpclose(fileDesc);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      end;
      { Set SoC pin 17 as output: }
      try
        fileDesc := fpopen('/sys/class/gpio/gpio17/direction', O_WrOnly);
        gReturnCode := fpwrite(fileDesc, OUT_DIRECTION[0], 3);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      finally
        gReturnCode := fpclose(fileDesc);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      end;
    end;
    
    procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    var
      fileDesc: integer;
    begin
      { Free SoC pin 17: }
      try
        fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
        gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      finally
        gReturnCode := fpclose(fileDesc);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      end;
    end;
    
    procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
    var
      fileDesc: integer;
    begin
      if GPIO17ToggleBox.Checked then
      begin
        { Swith SoC pin 17 on: }
        try
          fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
          gReturnCode := fpwrite(fileDesc, PIN_ON[0], 1);
          LogMemo.Lines.Add(IntToStr(gReturnCode));
        finally
          gReturnCode := fpclose(fileDesc);
          LogMemo.Lines.Add(IntToStr(gReturnCode));
        end;
      end
      else
      begin
        { Switch SoC pin 17 off: }
        try
          fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
          gReturnCode := fpwrite(fileDesc, PIN_OFF[0], 1);
          LogMemo.Lines.Add(IntToStr(gReturnCode));
        finally
          gReturnCode := fpclose(fileDesc);
          LogMemo.Lines.Add(IntToStr(gReturnCode));
        end;
      end;
    end;
    
    end.

Hauptprogramm:

pascal
program io_test;
    
    {$mode objfpc}{$H+}
    
    uses
      {$IFDEF UNIX}{$IFDEF UseCThreads}
      cthreads,
      {$ENDIF}{$ENDIF}
      Interfaces, // this includes the LCL widgetset
      Forms, Unit1
      { you can add units after this };
    
    {$R *.res}
    
    begin
      Application.Initialize;
      Application.CreateForm(TForm1, Form1);
      Application.Run;
    end.

Den Status eines Anschlusses lesen

/File:2013-04-28-193243_1280x1024_scrot.png

Demo-Programm, das den Status eines GPIO-Pins ausliest

/File:rpi_testcircuit_2d.png

Testschaltung für das o. a. Programm

/File:rpi_testcircuit_2p_annotaded.png

Beispiel für diese Testschaltung auf einer Steckplatine

Umgekehrt ist es natürlich auch möglich, den Status z. B. eines Schalters abzufragen, der mit dem GPIO-Port verbunden ist.

Das folgende einfache Beispiel ist dem vorherigen sehr ähnlich. Es benutzt den GPIO-Pin 18 als Eingang für ein binäres Gerät, z. B. einen Schalter, einen Transistor oder ein Relais. Das Programm enthält eine CheckBox mit der Bezeichnung GPIO18CheckBox und zur Aufzeichnung von Return-Codes ein TMemo-Feld mit dem Namen LogMemo.

Im Beispiel wurde ein Pol eines Tasters mit Pin 12 an der Anschlussleiste des Pi (entsprechend GPIO-Pin 18 des BCM2835 SOCs) und über einen 10-kOhm Pull-Up-Widerstand mit Pin 1 (+3.3V, siehe Schaltplan) verbunden. Der andere Pol wurde mit Pin 6 der Anschlussleiste (GND = Masse) verdrahtet. Das Programm liest den Status des Tasters aus und schaltet dementsprechend die CheckBox an oder aus.

Das Potential des Pins 18 ist hoch, wenn der Taster nicht gedrückt wird (wegen der Verbindung mit Pin 1 über den Pull-Up-Widerstand) und niedrig, wenn er gedrückt wird (da in dieser Situation Pin 18 über den Taster mit Masse verbunden wird). Der GPIO-Pin meldet daher 0, wenn der Taster gedrückt wird und 1, wenn er losgelassen wird.

Auch dieses Programm ist mit Root-Rechten auszuführen.

Steuerung-Unit:

pascal
unit Unit1;
    
    {Demo application for GPIO on Raspberry Pi}
    {Inspired by the Python input/output demo application by Gareth Halfacree}
    {written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
    
    {This application reads the status of a push-button}
    
    {$mode objfpc}{$H+}
    
    interface
    
    uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
      ButtonPanel, Unix, BaseUnix;
    
    type
    
      { TForm1 }
    
      TForm1 = class(TForm)
        ApplicationProperties1: TApplicationProperties;
        GPIO18CheckBox: TCheckBox;
        LogMemo: TMemo;
        procedure ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
        procedure FormActivate(Sender: TObject);
        procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
      private
        { private declarations }
      public
        { public declarations }
      end;
    
    const
      PIN_18: PChar = '18';
      IN_DIRECTION: PChar = 'in';
    
    var
      Form1: TForm1;
      gReturnCode: longint; {stores the result of the IO operation}
    
    implementation
    
    {$R *.lfm}
    
    { TForm1 }
    
    procedure TForm1.FormActivate(Sender: TObject);
    var
      fileDesc: integer;
    begin
      { Prepare SoC pin 18 (pin 12 on GPIO port) for access: }
      try
        fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
        gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      finally
        gReturnCode := fpclose(fileDesc);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      end;
      { Set SoC pin 18 as input: }
      try
        fileDesc := fpopen('/sys/class/gpio/gpio18/direction', O_WrOnly);
        gReturnCode := fpwrite(fileDesc, IN_DIRECTION[0], 2);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      finally
        gReturnCode := fpclose(fileDesc);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      end;
    end;
    
    procedure TForm1.ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
    var
      fileDesc: integer;
      buttonStatus: string[1] = '1';
    begin
      try
        { Open SoC pin 18 (pin 12 on GPIO port) in read-only mode: }
        fileDesc := fpopen('/sys/class/gpio/gpio18/value', O_RdOnly);
        if fileDesc > 0 then
        begin
          { Read status of this pin (0: button pressed, 1: button released): }
          gReturnCode := fpread(fileDesc, buttonStatus[1], 1);
          LogMemo.Lines.Add(IntToStr(gReturnCode) + ': ' + buttonStatus);
          LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
          if buttonStatus = '0' then
            GPIO18CheckBox.Checked := true
          else
            GPIO18CheckBox.Checked := false;
        end;
      finally
        { Close SoC pin 18 (pin 12 on GPIO port) }
        gReturnCode := fpclose(fileDesc);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
        LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
      end;
    end;
    
    procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    var
      fileDesc: integer;
    begin
      { Free SoC pin 18: }
      try
        fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
        gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      finally
        gReturnCode := fpclose(fileDesc);
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      end;
    end;
    
    end.

Das Hauptprogramm ist identisch zu dem des obigen Beispiels.

2. Hardware-Zugriff über gekapselte Shell-Aufrufe

Eine andere Möglichkeit, auf Hardware zuzugreifen, besteht in der Nutzung gekapselter Shell-Aufrufe. Dies geschieht mit Hilfe der fpsystem-Funktion. Auf diese Weise ist es möglich, auf Funktionen zuzugreifen, die von der BaseUnix-Unit nicht unterstützt werden. Der folgende Code hat die selbe Funktionalität wie das Programm des ersten Listings oben.

Steuerungs-Unit:

pascal
unit Unit1;
    
    {Demo application for GPIO on Raspberry Pi}
    {Inspired by the Python input/output demo application by Gareth Halfacree}
    {written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
    
    {$mode objfpc}{$H+}
    
    interface
    
    uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Unix;
    
    type
    
      { TForm1 }
    
      TForm1 = class(TForm)
        LogMemo: TMemo;
        GPIO17ToggleBox: TToggleBox;
        procedure FormActivate(Sender: TObject);
        procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
        procedure GPIO17ToggleBoxChange(Sender: TObject);
      private
        { private declarations }
      public
        { public declarations }
      end;
    
    var
      Form1: TForm1;
      gReturnCode: longint; {stores the result of the IO operation}
    
    implementation
    
    {$R *.lfm}
    
    { TForm1 }
    
    procedure TForm1.FormActivate(Sender: TObject);
    begin
      { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
      gReturnCode := fpsystem('echo "17" > /sys/class/gpio/export');
      LogMemo.Lines.Add(IntToStr(gReturnCode));
      { Set SoC pin 17 as output: }
      gReturnCode := fpsystem('echo "out" > /sys/class/gpio/gpio17/direction');
      LogMemo.Lines.Add(IntToStr(gReturnCode));
    end;
    
    procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    begin
      { Free SoC pin 17: }
      gReturnCode := fpsystem('echo "17" > /sys/class/gpio/unexport');
      LogMemo.Lines.Add(IntToStr(gReturnCode));
    end;
    
    procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
    begin
      if GPIO17ToggleBox.Checked then
      begin
        { Swith SoC pin 17 on: }
        gReturnCode := fpsystem('echo "1" > /sys/class/gpio/gpio17/value');
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      end
      else
      begin
        { Switch SoC pin 17 off: }
        gReturnCode := fpsystem('echo "0" > /sys/class/gpio/gpio17/value');
        LogMemo.Lines.Add(IntToStr(gReturnCode));
      end;
    end;
    
    end.

Das Hauptprogramm ist identisch zu dem der obigen Beispiele. Es erfordert wieder Root-Rechte.

3. wiringPi-Prozeduren und Funktionen

Mit Hilfe von Alex Schallers Wrapper-Unit für Gordon Hendersons Arduino-kompatible wiringPi-Bibliothek kann ein Nummerierungs-Schema verwendet werden, das dem der Arduino-Boards entspricht.

pascal
Function wiringPiSetup:longint; {Initialisiert das wiringPi-System entsprechend dem wiringPi Pin-Nummerierungs-Schema.}
    
    Procedure wiringPiGpioMode(mode:longint); {Initialisiert das wiringPi-System mit dem Broadcom GPIO-Pin-Nummerierungs-Schema.}
    
    Procedure pullUpDnControl(pin:longint; pud:longint); {steuert die internen pull-up/down-Widerstände eines GPIO-Pins.}
    
    Procedure pinMode(pin:longint; mode:longint); {setzt den Betriebsmodus eines Pins auf entweder INPUT, OUTPUT oder PWM_OUTPUT.}
    
    Procedure digitalWrite(pin:longint; value:longint); {setzt ein Ausgabe-Bit.}
    
    Procedure pwmWrite(pin:longint; value:longint); {setzt einen Ausgabe-PWM-Wert zwischen 0 und 1024.}
    
    Function digitalRead(pin:longint):longint;  {liest den Wert des übergebenen Pins, gibt 1 oder 0.}
    
    Procedure delay(howLong:dword); {wartet howLong Millisekunden.}
    
    Procedure delayMicroseconds(howLong:dword); {wartet howLong Mikrosekunden.}
    
    Function millis:dword; {gibt die Zahl der Millisekunden zurück, seit das Programm eine der wiringPiSetup-Funktionen aufgerufen hat.}

4. rpi_hal-Hardware Abstraction Library (GPIO, I2C und SPI Funktionen und Prozeduren)

Diese Unit mit ca. 1700 Lines of Code wird von Stefan Fischer zur Verfügung gestellt und bietet Prozeduren und Funktionen, die auf die rpi HW Zugriff auf I2C, SPI und GPIO bietet:

Ein Auszug der verfügbaren Funktionen und Prozeduren:

procedure gpio_set_pin (pin:longword;highlevel:boolean); { Set RPi GPIO pin to high or low level; Speed @ 700MHz -> 0.65MHz }

function gpio_get_PIN (pin:longword):boolean; { Get RPi GPIO pin Level is true when Pin level is '1'; false when '0'; Speed @ 700MHz -> 1.17MHz }

procedure gpio_set_input (pin:longword); { Set RPi GPIO pin to input direction }

procedure gpio_set_output(pin:longword); { Set RPi GPIO pin to output direction }

procedure gpio_set_alt (pin,altfunc:longword); { Set RPi GPIO pin to alternate function nr. 0..5 }

procedure gpio_set_gppud (mask:longword); { set RPi GPIO Pull-up/down Register (GPPUD) with mask }

...

function rpi_snr :string; { delivers SNR: 0000000012345678 }

function rpi_hw :string; { delivers Processor Type: BCM2708 }

function rpi_proc:string; { ARMv6-compatible processor rev 7 (v6l) }

...

function i2c_bus_write(baseadr,reg:word; var data:databuf_t; lgt:byte; testnr:integer) : integer;

function i2c_bus_read (baseadr,reg:word; var data:databuf_t; lgt:byte; testnr:integer) : integer;

function i2c_string_read(baseadr,reg:word; var data:databuf_t; lgt:byte; testnr:integer) : string;

function i2c_string_write(baseadr,reg:word; s:string; testnr:integer) : integer;

...

procedure SPI_Write(devnum:byte; reg,data:word);

function SPI_Read(devnum:byte; reg:word) : byte;

procedure SPI_BurstRead2Buffer (devnum,start_reg:byte; xferlen:longword);

procedure SPI_BurstWriteBuffer (devnum,start_reg:byte; xferlen:longword); { Write 'len' Bytes from Buffer SPI Dev startig at address 'reg' }

...

Test Program (testrpi.pas):

pascal
//Simple Test program, which is using rpi_hal;
    
      program testrpi;
      uses rpi_hal;
      begin
        writeln('Show CPU-Info, RPI-HW-Info and Registers:');
        rpi_show_all_info;
        writeln('Let Status LED Blink. Using GPIO functions:');
        GPIO_PIN_TOGGLE_TEST;
        writeln('Test SPI Read function. (piggy back board with installed RFM22B Module is required!)');
        Test_SPI;
      end.

5. PascalIO

Mit dem Package PascalIO kann objektorientiert auf die Schnittstellen zugegriffen werden. Es beinhaltet Klassen für die GPIO-Pins sowie für den I2C- und SPI-Bus.

GPIO

Input
pascal
program Project1;
    uses fpgpio;
    var
      pin_21: TGpioPin;
    begin
      pin_21 := TGpioLinuxPin.Create(21);
      pin_21.Direction := gdIn;
      WriteLn('Pin 21 hat den Wert: ', pin_21.Value);
      pin_21.Destroy;
    end.
Output
pascal
program Project1;
    uses sysutils, fpgpio;
    var
      i: Integer;
      pin_21: TGpioPin;
    begin
      pin_21 := TGpioLinuxPin.Create(21);
      pin_21.Direction := gdOut;
      for i := 0 to 10 do
      begin
        pin_21.Value := (i and $01) = 0;
        sleep(1000);
      end;
      pin_21.Destroy;
    end.
Interrupt
pascal
program Project1;
    uses fpgpio;
    var
      pin_21: TGpioPin;
      NewValue: Boolean;
    begin
      pin_21 := TGpioLinuxPin.Create(21);
      pin_21.Direction := gdIn;
      pin_21.InterruptMode := [gimRising, gimFalling];
      try
        repeat
          if input.WaitForInterrupt(TGpioLinuxPin.INTERRUPT_WAIT_INFINITE, NewValue) then
            Writeln('Interrupt on Pin ', input.PinID, ' with value ', NewValue)
          else
            WriteLn('Timeout');
        until False;
      except
        // e.g. on sig int
        pin_21.Destroy;
      end;
    end.

Literatur

Externe Links


From the Free Pascal wiki, page "Lazarus on Raspberry Pi/de", as the Internet Archive kept it on 2025-06-16, last changed on 2020-02-19. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.