Grundlagen der Schnittstellenprogrammierung

wiringPi - Die Schnittstelle zur Hardware

Linux macht es dem Programmierer traditionell nicht leicht, auf die Hardware des Rechners zuzugreifen. Was auf PCs und Servern durchaus sinnvoll ist, würde einem den Spaß am Raspberry gründlich verderben. Doch es gibt Wege. Verschiedene Bibliotheken stellen Funktionen zum direkten Zugriff auf die Register des SoC (System on Chip / Broadcom BCM2835) bereit. Die Schnittstellen sind meist in C geschrieben und lassen sich damit ohne größere Probleme in Pascal einbinden.

Zum Standard auf dem RPi haben sich die C-Bibliothen aus dem wiringPi-Projekt entwickelt. WiringPi ist im Raspbian-Repository enthalten. Die Aktualisierung bei neuen HW-Releases dürfte damit sichergestellt sein.

Die Bibliotheken müssen zur Laufzeit installiert sein. Vor dem Start eines Projektes sollte die Aktualität der Bibliotheken sichergestellt werden. Ein bereits installiertes Paket wird geprüft mit:

gpio -v

Die verfügbare Version im Repository prüfen:

apt-cache show wiringpi

Eine Versionsübersicht ist im Projekt zu finden. Aus diesen Informationen leitet sich der Installationsfall ab.

Fall A - Installation aus dem Repository:

sudo apt-get install wiringpi

Fall B - Installation aus den Quelldateien:
Vorbereitung -> ggf. eine frühere Version aus dem Repository entfernen und GIT installieren.

sudo apt-get purge wiringpi
sudo apt-get install git-core

Clonen und bauen/installieren

cd
git clone git://git.drogon.net/wiringPi
cd wiringPi
./build

Fall C - Aktualisierung vorhandener Quellen und neu bauen:

cd ~/wiringPi
git pull origin
./build

Testen:

gpio -v
gpio readall

In früheren Versionen von wiringPi waren Root-Rechte zur Ausführung einiger Funktionen erforderlich. Alternativ konnte die Variable WIRINGPI_GPIOMEM gesetzt werden. Auch wenn die Dokumentation noch nichts davon verrät (Stand Feb. 2017), können die Programme nun seit V2.38 mit normalen Nutzerrechten ausgeführt werden.
Ausnahme: Hardware-PWM !




Troubelshooting

Sollte nach der Installation die Version mit gpio -v nicht wie erwartet angezeigt werden => rebooten.

C-Bibliotheken in Pascal / wiringPi.pas

Die Verwendung von Funktionen aus C-Bibliothen in eigenen Pascalprogrammen ist recht simpel. Zur besseren Übersicht und im Interesse der Wiederverwendung sollten die Schnittstellen in einer separaten Unit definiert werden. Diese Unit wird in die eigenen Projekte eingebunden und bei Bedarf abwärtskompatibel erweitert.

Hier ein simples Beispiel:

unit wiringpi;

{$linklib c}
{$linklib libwiringPi}

interface
  function wiringPiSetup: longint; cdecl; external;
  procedure pinMode(pin: longint; mode: longint); cdecl; external;
  procedure pullUpDnControl(pin: longint; pud: longint); cdecl; external;
  procedure digitalWrite(pin: longint; value: longint); cdecl; external;
  function digitalRead(pin: longint): longint; cdecl; external;
  //.....
  	
implementation
end.
Die Definitionen werden aus der wiringPi-Referenz übernommen und dabei Schreibweise und Variablentypen an Pascal angepasst. Uses-Klauseln sind nicht erforderlich. Der Implementation-Block bleibt frei.

Beispiel - Aus einer C-Funktion wird die zugehörige Pascal-Procedure gebildet:

void pinMode (int pin, int mode) ;

procedure pinMode(pin: longint; mode: longint); cdecl; external;

Die möglichen Werte der Parameter können der Dokumentation oder besser den Header-Dateien der Bibliotheken entnommen werden. Zur besseren Übersicht sollten die möglichen Werte in Aufzählungstypen definiert werden.

Der Pfad zur Unit muss für den Compiler auffindbar sein:

Projekt-> Projekteinstellungen-> Compilereinstellungen-> Pfade-> Andere Units (-Fu)->
"../myLib/wiringPi"


Ein erweiterungsfähiges Grundgerüst eines Wrappers für wiringPi könnte wie folgt aussehen:

unit wiringpi;

{ Pascal wrapper unit for Gordon Henderson wiringPi library. The source can
  be found at https://http://wiringpi.com

 * wiringPi:
 *	Arduino compatable (ish) Wiring library for the Raspberry Pi
 *	Copyright (c) 2012 Gordon Henderson
 ***********************************************************************
 * This file is part of wiringPi:
 *	https://projects.drogon.net/raspberry-pi/wiringpi/
 *
 *    wiringPi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    wiringPi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with wiringPi.  If not, see .
 ***********************************************************************
}

{$linklib c}
{$linklib libwiringPi}

interface

//uses ;

type  //redefinition of wirinPi-Const - s. wirinPi.h

  //set in tPinMode  => int 0..6
  tPinMode = (pmINPUT, pmOUTPUT, pmPWM_OUTPUT, pmGPIO_CLOCK, pmSOFT_PWM_OUTPUT,
              pmSOFT_TONE_OUTPUT, pmPWM_TONE_OUTPUT);

  //digitalRead, digitalWrite => int 0..1
  tLevel =(levLOW, levHIGH);

  //set in pullUpDownControl => int 0..2
  tPull = (pullOFF,	pullDOWN,	pullUP);

  //set edge for Interrupt => int 0..3
  tIntMode = (intSetup, intFalling, intRising, intBoth);

  //set PWM => int 0..1
  tPWMMode = (pwmMS, pwmBAL);

  //set in pinModeAlt => int 0..7  -> FSEL9 0-7
  tAltMode = (amIN, amOUT, amALT5, amALT4, amALT0, amALT1, amALT2, amALT3);

//-----------------------------------------------------------------------------

//Setup - Funktionen
//==================
// http://wiringpi.com/reference/setup/


function wiringPiSetup : longint; cdecl; external;
function wiringPiSetupGpio: longint; cdecl; external;
function wiringPiSetupPhys: longint; cdecl; external;
function wiringPiSetupSys: longint; cdecl; external;


// Core Functions
// ==============
// http://wiringpi.com/reference/core-functions/

procedure pinMode(pin:longint; mode: tPinMode); cdecl; external;
procedure pullUpDnControl(pin: longint; pud: tPull); cdecl; external;
procedure digitalWrite(pin: longint; value: tLevel); cdecl; external;
function  digitalRead(pin: longint): tLevel; cdecl; external;


//undocumented GPIO - functions ------------------------------------------------

procedure pinModeAlt (pin: longint; mode: tAltMode); cdecl; external;
function  getAlt(pi: longint): longint; cdecl; external;


//Interrupt and Thread ---------------------------------------------------------
//http://wiringpi.com/reference/priority-interrupts-and-threads/

function wiringPiISR(pin: longint; mode: tIntMode; pcallbback: pointer):longint; cdecl; external;
{
Lazarus:
-> pcallback has to be a global procedure
-> It starts a separate thread !!!
-> It's NOT synchronized with LCL  !!! use e.g. Application.QueueAsyncCall(...)
}



//RS232 ------------------------------------------------------------------------
//http://wiringpi.com/reference/serial-library/

function  serialOpen (device: pchar; baud: longint): longint; cdecl; external;
procedure serialClose (fd: longint); cdecl; external;
procedure serialPutchar (fd: longint; c: byte) ; cdecl; external;
procedure serialPuts (fd: longint; s: pchar) ; cdecl; external;
function  serialDataAvail (fd: longint): longint; cdecl; external;
function  serialGetchar (fd: longint): integer ; cdecl; external;
procedure serialFlush (fd: longint) ; cdecl; external;

//------------------------------------------------------------------------------

//HW - PWM - (root-permissions)
procedure pwmSetMode(mode: tPWMMode); cdecl; external;
procedure pwmSetRange(range: dword); cdecl; external;
procedure pwmSetClock(divisor: longint); cdecl; external;
procedure pwmWrite(pin: longint; value: longint); cdecl; external;

//SW - PWM  (user-permissions)
function softPwmCreate(pin: longint; initialValue: longint; pwmRange: longint): longint; cdecl; external;
procedure softPwmWrite(pin: longint; value: longint); cdecl; external;
{
 value =    x * 100µs
 pwmRange = x * 100µs
 -> one Thread per pin
 -> only one create per pin on runtime, range not changeable
}

//Soft-Tone
function  softToneCreate (pin: longint): longint; cdecl; external;
procedure softToneWrite (pin: longint; freq: longint); cdecl; external;
{
 freq in Hz
 f <= 1kHz -> ok
 f >  1kHz -> bad accurancy
}

// -----------------------------------------------------------------------------

//undocumented procedure
procedure pwmToneWrite(pin: longint; freq: longint); cdecl; external;
procedure gpioClockSet(pin: longint; freq: longint); cdecl; external;

//------------------------------------------------------------------------------

//Pin-Translation

function wpiPinToGpio(wpiPin:longint):longint; cdecl; external;
function physPinToGpio(physPin:longint):longint; cdecl; external;

//------------------------------------------------------------------------------


function piGpioLayout(): longint; cdecl; external;


//------------------------------------------------------------------------------

implementation



end.

Einige Funktionen arbeiten mit Threads. Dies erfordert das Einbinden von cthreads als erste Unit im Programmcode. Das kann durch Definition des Symbols UseCThreads über Setzen der Compileroption -dUseCThreads erreicht werden.

Projekt-> Projekteinstellungen-> Compilereinstellungen-> Benutzerdefinierte Einstellungen

Damit wird die Klausel in der *.lpr - Datei aktiviert.

Als zweite Unit solle cmem aufgenommen werden. Damit verwendet das Programm den C-Memory-Manager, dem eine bessere Speicherverwaltung nachgesagt wird.

...
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads, cmem,
  {$ENDIF}{$ENDIF}
  Interfaces, 
  ....

wiringPi Setup

Die Benutzung der Funktionen setzt zwingend den Aufruf einer von drei Setup-Funktionen voraus. Darin wird hauptsächlich das Zählschema der Pins für alle weiteren Funktionen festgelegt. WiringPi führt zur Kompatiblität der RPi-Revisionen ein eigenes Zählschema ein. Neben wiringPi lassen sich die Zählweise des Broadcom-Chip und die Pinzuordnung des P1-Headers initialisieren.

  • function wiringPiSetup: longint; cdecl; external; //wiringPi-Schema
  • function wiringPiSetupGpio: longint; cdecl; external; //Broadcom-Schema
  • function wiringPiSetupPhys: longint; cdecl; external; //P1-Connector

Der Setup sollte zum Programmstart bspw. in Formcreate des Hauptfensters aufgerufen werden. Die Funktionen liefern ein Integer-Ergebnis zurück, das allerdings immer 0 ist.

Seit V2.38 können die Setup-Funktionen mit normalen User-Rechten ausgeführt werden. Root-Rechte oder das Setzen einer Umgebungsvariablen sind nicht mehr erforderlich. Es muss nur sichergestellt sein, dass der ausführende User der Gruppe GPIO angehört.

Nachtrag:
Hardware-PWM erfordert weiterhin root-Rechte. Die Ausführung des Befehls
pinMode(1, pmPWM_OUTPUT);
führt bei normalen Usern zu Programm- bzw Systemabstürzen.



Pin-Schema und Alternativ-Funktionen:

RPi GPIO Schema
RPi PinSceme
Ansicht / Download
BCM2835 Alt-Modes
SoC Functions
Ansicht / Download / Quelle

Pin Modes

Das Setzen und Lesen einzlner GPIO dürfte die einfachste Aufgabe sein. Vor einer IO-Procedure muss der Pin-Mode definiert werden.

pinMode(pin, mode); 
Folgende Modi sind möglich:
  • 0: pmINPUT
  • 1: pmOUTPUT
  • 2: pmPWM_OUTPUT (*1)
  • 3: pmGPIO_CLOCK (*1)
  • 4: pmSOFT_PWM_OUTPUT
  • 5: pmSOFT_TONE_OUTPUT
  • 6: pmPWM_TONE_OUTPUT
*1) nur als root zulässig

Bei einem Eingang kann es sinvoll sein, den Pin auf H- oder L-Level zu ziehen.

pullUpDnControl(pin, pud); 
  • 0: pullOFF
  • 1: pullDOWN
  • 2: pullUP




Digitales Lesen und Schreiben

Digitales Lesen und Schreiben ist nach Setup und Initialisierug mit diesen Funktionen möglich:

value:= digitalRead(pin); // pin: longint; value: tLevel
digitalWrite(pin, value); // pin: longint; value: tLevel
tLevel kann folgende Werte annehmen:
  • 0: levLOW
  • 1: levHIGH




Interrupts

Zur Reaktion auf Pegeländerungen an GPIO-Pins lassen sich mit der Funktion wiringPiISR Interrup-Service-Routinen einrichten.

res:= wiringPiISR(pin, intRising, @Callback);
Das zurückgelieferte Ergennis ist im Erfolgsfall 0.

Der 2. Parameter kann folgede Werte annehmen:

  • 0: intSetup
  • 1: intFalling
  • 2: intRising
  • 3: intBoth
intSetup übernimmt eine zuvor gesetzte Flanke und ändert lediglich die Callback-Adresse für das Pin. Zum 3. Parameter gleich mehr.

Einige Dinge gilt es zu beachten:

1. Die Unit cthreads muss eingebunden sein ( s.o. ).

2. Der Callback-Parameter muss ein Pointer auf eine globale Procedure sein. Es darf nicht der Pointer auf die Methode einer Klasse sein. Dies würde nicht dem erwarteten Zeigertyp entspechen und den Callback ins Nirvana schicken.

3. Der Callback kommt aus einem separaten Thread, d.h. auch die Callback-Procedure im Pascal-Programm läuft in diesem Thread. Es ist unzulässig, von dort auf Componenten der LCL zuzugreifen. Dies würde früher oder später zum Absturz führen. Das Problem kann gelöst werden, indem der Mainthread lediglich über das Ereignis informiert wird und selbst entscheiden kann, wann er den Code in seinem eigenen Thread ausführen möchte.

Hier ein Minimalprogramm. Der Befehl Application.QueueAsyncCall schickt eine Message an das Hauptfenster. Der Parameter wird hier nicht genutzt. Beispiel

unit main;

{$mode delphi}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, wiringPi;

type
TISREvent = procedure(x: longint) of object;

type
TForm1 = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
  private
    procedure Changed(x: longint);
  public
  
  end;

var Form1: TForm1;

implementation

{$R *.lfm}

//------------------------------------------------
//global Callback
var event0: tISREvent;
procedure Global_Callback;
begin
  //Send a message to MainThread
  Application.QueueAsyncCall(event0, 0);
end;
//----------------------------------------------

procedure TForm1.FormCreate(Sender: TObject);
var err: integer;
begin
  wiringPiSetup(); //Setup in WiringPi-Numbering
  pinmode(4, pmINPUT);
  pullUpDnControl(4, pullUp);	// -> 3,3V

  //Callback initialize
  event0:= Self.Changed;
  err:= wiringPiISR(4, intRising, @Global_Callback);
end;

procedure TForm1.Changed(x: longint);
begin
  Label1.Caption:= 'Interrupt detected';
end;

end.

Ein Beispiel zur Anwendung von Drehimpulsgebern als Eingabegerät ist in Github zu finden




Hardware - PWM

Eins vornweg: Hardware-PWM funktioniert derzeit nur mit Root-Rechten. Der Versuch den PinMode auf pmPWM_OUTPUT zu setzen, schickt das System sonst ins Nirvana.

Beim Rapsberry steht nur einer der beiden PWM-Kanäle zur Verfügung. PWM0 (BCM.GPIO18) ist fest mit P1.12 / GPIO.1 verbunden. PWM1 (BCM.GPIO19) ist nicht nutzbar. Außerdem wird PWM0 intern zur analogen Soundausgabe genutzt.

Auch wenn dadurch der praktischen Nutzung enge Grenzen gesetzt sind, hier die Anwendung:

//Init HW-PWM GPIO.1
pinMode(1, pmPWM_OUTPUT); //switch BCM.18 to ALT5, sudo needed
pwmSetMode(pwmMS);        //pwmMS -> Mark:Space || pwmBAL -> Balanced
pwmSetClock(100);         //clock = 19.2MHz div clockdiv  (32bit) (>= 2)
pwmSetRange(1024);        //range  (32bit)
pwmWrite(1, 128);         //value  (32bit)


Timing der PWM-Modes mit o.g. Werten:

Mark:Space  f=187,5Hz
Mark:Space
t periode = ( clockdiv range ) 19200 ms t mark = t periode ( value range ) ms alignl t_periode=("clockdiv" * "range") over {19200} ms newline alignl t_mark=t_periode*( value over range ) ms
Balanced  f=24,0kHz
Balenced
t periode = ( range value ) clockdiv 19200 ms t mark = clockdiv 19200 ms alignl t_periode={("range" over "value") * "clockdiv"} over {19200} ms newline alignl t_mark= "clockdiv" over {19200} ms




Software - PWM

Zur Umgehung der HW-Beschränkungen bietet wiringPi eine Schnittstelle zur programmtechnischen Ansteuerung der GPIO mit PWM-Signalen. Die Ausführung ist mit user-Rechten möglich. Wie bei allen Schnittstellen muss der User aber der Gruppe gpio angehören. Es können alle freien GPIO angesteuert werden. Für jedes Pin wird ein separater Thread gestartet, d.h. die unit cthreads muss eingebunden sein. Die Threads werden mit dem Hauptprogramm beendet. Eine Schnittstelle zur vorzeitigen Ende gibt es nicht.

res:= softPwmCreate(pin, startvalue, range);
Das Ergebnis ist im Erfolgsfall = 0. Die Funktion kann nur 1x je Pin aufgerufen und range später nicht geändert werden.

tmark wird zur Laufzeit geändert mit:

softPwmWrite(pin, value);

tPeriode = range * 100µs
tMark    = value * 100µs

An die Genauigkeit sollten keine zu hohen Erwartungen gestellt werden. range-Werte >=100 sind ok. Geringere Werte verursachen Jitter und erhöhen die Prozessorlast.




Soft - Töne

Thematisch verwandt mit den Funktionen der Software-PWM ist die softwaregesteuerte Frequenzausgabe.

softToneCreate (pin);
Das Ergebnis ist im Erfolgsfall = 0. Die Funktion kann nur 1x je Pin aufgerufen werden.

fPin wird gesetzt mit:

softToneWrite (frequenz);
Wert der frequenz in Hz. frequenz = 0 zieht den Ausgang auf low.

Auch hier treten wieder Probleme mit Jitter und Prozessorlast auf. Frequenzen bis 100Hz sind gut beherrschbar. Auch kurze Kontrolltöne mit ca. 1kHz sind möglich. Die Sinnhaftigkeit der Nutzung hängt vom Einsatzfall ab.

Der Raspberry und seine UnARTen

Der SoC BCM283X verfügt über zwei asynchrone serielle Schnittstellen, UART0 und UART1. Beide unterscheiden sich in Ihrer Funktionalität und schließen sich durch die Beschaltung des P1-Header gegenseitig aus. Die UART-Module lassen sich zwar über die Alt-Modi auf verschiedene Ausgänge mappen, davon sind allerdings nur BCM.14+15 auf P1.8+10 geführt. Beim RP3 besteht allerdings die Möglichkeit einen UART auf den P1-Header zu mappen und den anderen per Bluetooth zu koppeln.

Folgende Eingenschaften bzw. Eigenheiten sind zu beachten:

UART0: vollwertiger UART
   - entspricht UART 16550 - Standard
   - fester Datentakt
   - beim RPi3 auf das Bluetooth-Modul geschaltet

UART1: Mini-UART mit eingeschränkter Funktionalität
  - nur 8 bzw 7 Bit Datenbreite
  - keine Parität
  - nur 1 Stopbit
  - Datentakt von der Core-Frequenz abhängig !!!

Aktivieren der UART

Per default steuert der UART0 das BT-Modul und der UART1 ist deaktiviert.
Beim RPi3 werden folgende Gerätenamen verwandt:

  • UART0:       ttyAMA0
  • UART1:       ttyS0
  • USB-Adapter: ttyUSB0

Es ist darauf zu achten, dass der ausführende User der Gruppe dialout angehört. Dies ist beim Standarduser pi der default der Fall (Test: id).

UART1

Sollte die Funktionalität des Mini-UART ausreichen, genügt es, die serielle Schnittstelle per sudo raspi-config zu aktivieren. Dabei ist die Frage nach Aktivierung der login shell mit nein zu beantworten.

Alternativ kann in der Datei /boot/config.txt der Eintrag enable_uart=1 hinzugefügt bzw. aktiviert, sowie in /boot/cmdline.txt den Eintrag console=serial0,115200 entfernt werden, falls vorhanden. Dies verhindert das Laden der Unit getty@ttyS0, die sonst die Schnittstelle für das System blockieren würde.

Folgende Nebenwirkungen stellen sich ein:

  - Die Rx/Tx-Pins werden nach ALT5 auf den UART1 gemappt
  - Die Core-Frequenz wird fest auf 250MHz herabgesetzt
  - Das Gerät ttyS0 wird aktiviert und der Gruppe dialout zugeordnet
  - Die Gruppe dialout erhält rw-Rechte
  - Der symbolische Link serial0 verweist auf ttyS0


UART0

Auch hier muss die serielle Schnittstelle wie beim UART1 beschrieben aktiviert werden. Zur Umschaltung des UART0 auf den P1-Header muss die Verbindung zum BT-Modul getrennt werden. Wahlweise lässt sich BT komplett deaktivieren oder auf UART1 schalten.

Passendes Overlay beim booten laden:

sudo nano /boot/config.txt
Zur Abschaltung des BT-Moduls folgende Zeile anfügen:
dtoverlay=pi3-disable-bt
oder zur Umschaltung auf UART1
dtoverlay=pi3-miniuart-bt
core_freq=250
Zur Stabilisierung der Datenrate muss die Core-Frequenz in diesem Fall separat festgelegt werden.

Ggf. UART-BT-Treiber deaktivieren:

sudo systemctl disable hciuart
Reboot nicht vergessen.

Folgendes sollte sich einstellen:

  - Die Rx/Tx-Pins werden nach ALT0 auf den UART0 gemappt
  - Symbolischer Link: serial0 -> ttyAMA0
  - Symbolischer Link: serial1 -> ttyS0
  - Beide Geräte in der Gruppe dialout mit rw-Rechten


Testmöglichkeiten:

gpio readall
for src in sdram_freq core_freq gpu_freq ; \
do echo -e "$src:\t$(vcgencmd get_config $src)" ; \
done
ls -l /dev | grep 'ttyS0\|ttyAMA0\|ttyUSB'
Sollten sich die erwarteten Ergebnisse nicht einstellen -> Die serielle Schnittstelle über raspi-config deaktivieren und nach reboot wieder aktivieren.


Schnittstellenparameter

Über wiringPi lässt sich lediglich die Baurate beim Öffnen der Schnittstelle einstellen. Das Übertragungsformat wird mit 8N1 fetgelegt. Davon abweichende Parameter lassen sich über die Freepascal-RTL termio setzen.
  tcgetattr(fd, tios);             //unit termio
  tios.c_cc[VTIME]:= RxTimeout;    //rx timeout  n * 0.1sec

  //only CS8, CS7 for mini-UART1
  tios.c_cflag := tios.c_cflag and not CSIZE;
  case DataBits of
    db5: tios.c_cflag:=tios.c_cflag or CS5;	
    db6: tios.c_cflag:=tios.c_cflag or CS6;
    db7: tios.c_cflag:=tios.c_cflag or CS7;
    db8: tios.c_cflag:=tios.c_cflag or CS8;
  end;

  //Parity not available on UART1 (mini-UART)
  tios.c_cflag:= tios.c_cflag and not PARENB;		//Parity off
  case Parity of  //default none Parity
  	paOdd:  tios.c_cflag:= tios.c_cflag or PARENB or PARODD;  // Enable + odd parity
  	paEven: tios.c_cflag:= tios.c_cflag or PARENB;  // Enable + not odd (even) parity
  end;

  //One or Two Stopbits (only one for UART1)
  tios.c_cflag:= tios.c_cflag and not CSTOPB;		//one Stopbit
  if Stopbits = sbTwo then
     tios.c_cflag:= tios.c_cflag or CSTOPB;

  //RTS - CTS - Flowcontrol
  tios.c_cflag:= tios.c_cflag and not CRTSCTS;  //fcNone
  if FlowControl = fcHardware then
    tios.c_cflag:= tios.c_cflag or CRTSCTS;

  if tcsetattr(fd, TCSANOW, tios) <> 0 then begin  //set immidiately
    result:= -1;
    exit;
  end; 
Komplette unit

Beide UART gestatten ein RTS/CTS-Flowcontrol. Dazu müssen die Steuerleitungen entsprechend gemappt werden.

  • UART0-CTS -> ALT3 -> BCM.16 => GPIO.27 => P1.36
  • UART0-RTS -> ALT3 -> BCM.17 => GPIO.0  => P1.11

  • UART1-CTS -> ALT5 -> BCM.16 => GPIO.27 => P1.36
  • UART1-RTS -> ALT5 -> BCM.17 => GPIO.0  => P1.11

Fazit:

In den zurückliegenden HW/SW-Revisionen wurde das Prozedere zur Schnittstellenaktivierung desöfteren geändert, sodass nicht davon auszugehen ist, dass o.g. Verfahren lange Bestand haben wird.
Angesichts der Einschränkungen lassen sich die internen UART nur sinnvoll nutzen, wenn direkt mit 3,3V-Pegel gearbeitet werden soll. Falls V24-Pegel erforderlich sind, wäre die Verwendung eines USB-RS232-Adapters sinnvoller.

nach oben