Hi Thaddy,
It seems Raspberry Pi related example codes on wiki pages are not up to date, or I am doing something terribly wrong.
Below is my unit:
unit uGPIO;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
DateUtils,
Forms,
BaseUnix;
procedure Log(const Value: string);
function SetupGPIO(const Pin: PChar; Direction: PChar): Boolean;
function ReleaseGPIO(const Pin: PChar): Boolean;
function SetGPIOPinOut(const Pin: PChar): Boolean;
function SetGPIOPinIn(const Pin: PChar): Boolean;
const
PIN_OUT: PChar = 'out';
PIN_IN: PChar = 'in';
PIN_ON: PChar = '1';
PIN_OFF: PChar = '0';
PIN_1: PChar = '1';
PIN_2: PChar = '2';
PIN_3: PChar = '3';
PIN_4: PChar = '4';
PIN_5: PChar = '5';
PIN_6: PChar = '6';
PIN_7: PChar = '7';
PIN_8: PChar = '8';
PIN_9: PChar = '9';
PIN_10: PChar = '10';
PIN_11: PChar = '11';
PIN_12: PChar = '12';
PIN_13: PChar = '13';
PIN_14: PChar = '14';
PIN_15: PChar = '15';
PIN_16: PChar = '16';
PIN_17: PChar = '17';
PIN_18: PChar = '18';
PIN_19: PChar = '19';
PIN_20: PChar = '20';
PIN_21: PChar = '21';
PIN_22: PChar = '22';
PIN_23: PChar = '23';
PIN_24: PChar = '24';
PIN_25: PChar = '25';
PIN_26: PChar = '26';
PIN_27: PChar = '27';
PIN_28: PChar = '28';
PIN_29: PChar = '29';
PIN_30: PChar = '30';
PIN_31: PChar = '31';
PIN_32: PChar = '32';
PIN_33: PChar = '33';
PIN_34: PChar = '34';
PIN_35: PChar = '35';
PIN_36: PChar = '36';
PIN_37: PChar = '37';
PIN_38: PChar = '38';
PIN_39: PChar = '39';
PIN_40: PChar = '40';
var
BasePath: string;
LogFileName: string;
implementation
procedure Log(const Value: string);
var
F: TextFile;
Prefix: string;
begin
LogFileName := BasePath + 'log/' + FormatDateTime('yyyy-mm-dd', Now()) + '.log';
AssignFile(F, LogFileName);
{$I-}
if FileExists(LogFileName) then
Append(F)
else
ReWrite(F);
if IOResult <> 0 then Exit();
try
Prefix := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz ', Now());
Prefix := Prefix + StringReplace(Value, #13, ' ', [rfReplaceAll]);
Prefix := StringReplace(Prefix, #10, ' ', [rfReplaceAll]);
WriteLn(F, Prefix);
finally
CloseFile(F);
{$I+}
end;
end;
// Use physical pin number. Not GPIO Number
function SetupGPIO(const Pin: PChar; Direction: PChar): Boolean;
var
FileDesc: Integer;
ReturnCode: Longint;
begin
if (Direction <> 'out') and (Direction <> 'in') then
begin
Log('SetupGPIO: wrong direction parameter: ' + QuotedStr(StrPas(Direction)));
Exit(False);
end;
try
FileDesc := FpOpen('/sys/class/gpio/export', O_WrOnly);
if FileDesc <= 0 then
begin
Result := False;
Log('SetupGPIO-fpopen: ' + SysErrorMessage(FpGetErrNo()));
end;
ReturnCode := fpwrite(FileDesc, Pin[0], Length(Pin));
if ReturnCode = -1 then
begin
Result := False;
Log('SetupGPIO-fpwrite: ' + SysErrorMessage(FpGetErrNo()));
end;
finally
ReturnCode := fpclose(fileDesc);
if ReturnCode <> 0 then
begin
Log('SetupGPIO-fpclose' + SysErrorMessage(FpGetErrNo()));
end;
end;
if Result then
begin
if Direction = 'out' then
Result := SetGPIOPinOut(Pin)
else
Result := SetGPIOPinIn(Pin);
end;
if Result then Log('SetupGPIO: Pin: ' + StrPas(Pin) + ' - success');
end;
// Use physical pin number. Not GPIO Number
function ReleaseGPIO(const Pin: PChar): Boolean;
var
FileDesc: Integer;
ReturnCode: Longint;
begin
try
FileDesc := FpOpen('/sys/class/gpio/unexport', O_WrOnly);
if FileDesc <= 0 then
begin
Result := False;
Log('ReleaseGPIO-fpopen: ' + SysErrorMessage(FpGetErrNo()));
end;
if Result then
begin
ReturnCode := fpwrite(FileDesc, Pin[0], Length(Pin));
if ReturnCode = -1 then
begin
Result := False;
Log('ReleaseGPIO-fpwrite: ' + SysErrorMessage(FpGetErrNo()));
end;
end;
finally
ReturnCode := fpclose(fileDesc);
if ReturnCode <> 0 then
begin
Log('SetupGPIO-fpclose' + SysErrorMessage(FpGetErrNo()));
end;
end;
// Return True in anyway
Result := True;
Log('ReleaseGPIO: Pin: ' + StrPas(Pin) + ' - success');
end;
function SetGPIOPinOut(const Pin: PChar): Boolean;
var
FileName: ShortString;
FileDesc: Integer;
ReturnCode: Longint;
begin
FileName := '/sys/class/gpio/gpio' + StrPas(Pin) + '/direction';
Log('SetGPIOPinOut: FileName: ' + FileName);
Result := True;
try
FileDesc := FpOpen(FileName, O_WrOnly);
if FileDesc <= 0 then
begin
Result := False;
Log('InitGPIOPin-fpopen: ' + SysErrorMessage(FpGetErrNo()));
end;
if Result then
begin
ReturnCode := fpwrite(FileDesc, 'out', 3);
if ReturnCode = -1 then
begin
Result := False;
Log('InitGPIOPin-fpwrite: ' + SysErrorMessage(FpGetErrNo()));
end;
end;
finally
ReturnCode := fpclose(fileDesc);
if ReturnCode <> 0 then
begin
Log('SetGPIOPinOut-fpclose: ' + SysErrorMessage(FpGetErrNo()));
end;
end;
end;
function SetGPIOPinIn(const Pin: PChar): Boolean;
var
FileName: ShortString;
FileDesc: Integer;
ReturnCode: Longint;
begin
FileName := '/sys/class/gpio/gpio' + StrPas(Pin) + '/direction';
Log('SetGPIOPinIn: FileName: ' + FileName);
Result := True;
try
FileDesc := FpOpen(FileName, O_WrOnly);
if FileDesc <= 0 then
begin
Result := False;
Log('SetGPIOPinIn-fpopen: ' + SysErrorMessage(FpGetErrNo()));
end;
if Result then
begin
ReturnCode := fpwrite(FileDesc, 'in', 2);
if ReturnCode = -1 then
begin
Result := False;
Log('SetGPIOPinIn-fpwrite: ' + SysErrorMessage(FpGetErrNo()));
end;
end;
finally
ReturnCode := fpclose(fileDesc);
if ReturnCode <> 0 then
begin
Log('SetGPIOPinIn-fpclose: ' + SysErrorMessage(FpGetErrNo()));
end;
end;
end;
initialization
BasePath := ExtractFilePath(Application.ExeName);
if not DirectoryExists(BasePath + '/log') then ForceDirectories(BasePath + '/log');
Log('uGPIO initialization');
end.
Trying to setup PIN23 and PIN24 using:
// On FormCreate()
SetupGPIO(PIN_23, PIN_OUT);
SetupGPIO(PIN_24, PIN_IN);
// On FormDestroy
ReleaseGPIO(PIN_23);
ReleaseGPIO(PIN_24);
Gives me following error lines in my log file:
2017-03-06 09:37:01.658 uGPIO initialization
2017-03-06 09:37:01.913 SetGPIOPinOut: FileName: /sys/class/gpio/gpio23/direction
2017-03-06 09:37:01.913 InitGPIOPin-fpopen: Permission denied
2017-03-06 09:37:01.914 SetGPIOPinOut-fpclose: Bad file number
2017-03-06 09:37:26.457 ReleaseGPIO: Pin: 23 - success
2017-03-06 09:37:26.458 ReleaseGPIO: Pin: 24 - success
My /sys/class/gpio output is:
pi@raspberrypi:~ $ ls -l /sys/class/gpio/
toplam 0
-rwxrwx--- 1 root gpio 4096 Mar 2 09:05 export
lrwxrwxrwx 1 root gpio 0 Mar 6 09:37 gpio23 -> ../../devices/platform/soc/3f200000.gpio/gpio/gpio23
lrwxrwxrwx 1 root gpio 0 Mar 2 09:05 gpiochip0 -> ../../devices/platform/soc/3f200000.gpio/gpio/gpiochip0
lrwxrwxrwx 1 root gpio 0 Mar 2 09:05 gpiochip100 -> ../../devices/platform/soc/soc:virtgpio/gpio/gpiochip100
-rwxrwx--- 1 root gpio 4096 Mar 2 09:05 unexport
pi@raspberrypi:~ $
pi@raspberrypi:~ $ ls -l /sys/class/gpio/gpio23/
toplam 0
-rwxrwx--- 1 root gpio 4096 Mar 6 09:37 active_low
lrwxrwxrwx 1 root gpio 0 Mar 6 09:37 device -> ../../../3f200000.gpio
-rwxrwx--- 1 root gpio 4096 Mar 6 09:37 direction
-rwxrwx--- 1 root gpio 4096 Mar 6 09:37 edge
drwxrwx--- 2 root gpio 0 Mar 6 09:37 power
lrwxrwxrwx 1 root gpio 0 Mar 6 09:37 subsystem -> ../../../../../../class/gpio
-rwxrwx--- 1 root gpio 4096 Mar 6 09:37 uevent
-rwxrwx--- 1 root gpio 4096 Mar 6 09:37 value
pi@raspberrypi:~ $
So, my question is:
System creates a symbolic link once I try to set a pin for export?
My observations:
- As document indicates nothing about permissions. However, it seems I need to be at least a member of gpio group in order to be able to set directions. Though, python scripts has no trouble using IO ports with same user (pi) as my application runs. I cant understand why exporting port is successfull but not setting it for output or input is a fail?
- PXL (Platform eXtended Library) for low level native access to GPIO raised an exception for me with message "Cannot open file /dev/mem for memory mapping. Can this be related with permissions?
I do not want to run my application as root or some other privileged user. As you are also working with Raspberry Pi, I appreciate if you share your experience, please.
Thanks & regards,
-Ertan