Raspberry Pi - SPI/de
Nutzung der SPI-Schnittstelle am Raspberry Pi mit Freepascal
Gleich vorweg: Es ist eine gute Idee, für die Hardwarekomponenten wie SPI, I2C und GPIOs des Raspberry Pi die pascalio Lib (https://github.com/SAmeis/pascalio) zu verwenden.
Allerdings ist die pascalio auch sehr umfangreich und wer verstehen möchte, was da passiert, ist vielleicht mit dieser Anleitung ganz gut bedient.
SPI unter Linux
Auch für die SPI-Schnittstelle gilt das Linux-Prinzip "Alles ist eine Datei". Den Vorteil, dass man mit einfachen Dateizugriffen auf die Schnittstelle zugreifen kann erkauft man sich allerdings mit geringerer Geschwindigkeit - meist unkritisch - und damit, dass auch andere Programme auf die gleiche Schnittstelle zugreifen können.
Auf dem Raspberry Pi (wir reden hier von Version 3 mit Raspbian Stretch, Stand Okt 2017) gibt es eine SPI-Schnittstelle, die 2 Devices ansprechen kann: /dev/spidev0.0 und /dev/spidev0.1
Zu den Grundlagen von SPI, Master-Slave, Verdrahtung siehe Wikipedia: https://de.wikipedia.org/wiki/Serial_Peripheral_Interface
Header
unit test_spi;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, BaseUnix, UnixType;
type
Tspi = class
procedure Init();
procedure Close();
function DataIn(var din; cnt : integer) : integer;
function DataOut(const dout; cnt : integer) : integer;
procedure TransferSync(const dout; var din; len : integer);
procedure TransmitSync(const dout; len : integer);
function FastShift(dout : shortint) : shortint;
private
{ private declarations }
public
{ public declarations }
end;
const
// SPI Mode Flags
cSPI_CPHA = $01;
cSPI_CPOL = $02;
cSPI_MODE_0 = (0 or 0);
cSPI_MODE_1 = (0 or SPI_CPHA);
cSPI_MODE_2 = (SPI_CPOL or 0);
cSPI_MODE_3 = (SPI_CPOL or SPI_CPHA);
cSPI_CS_HIGH = $04;
cSPI_LSB_FIRST = $08;
cSPI_3WIRE = $10;
cSPI_LOOP = $20;
cSPI_NO_CS = $40;
cSPI_READY = $80;
cSPI_CTRL = $6B; // ist das "Magic Byte"
// Controlregister
// Read/Write + Size + MagicByte + Register
cSPI_RD_MODE : uint32 = $80016B01;
cSPI_WR_MODE : uint32 = $40016B01;
cSPI_RD_LSB_FIRST : uint32 = $80016B02;
cSPI_WR_LSB_FIRST : uint32 = $40016B02;
cSPI_RD_BITS_PER_WORD : uint32 = $80016B03;
cSPI_WR_BITS_PER_WORD : uint32 = $40016B03;
cSPI_RD_MAX_SPEED_HZ : uint32 = $80046B04;
cSPI_WR_MAX_SPEED_HZ : uint32 = $40046B04;
cSPI_DEVICE = '/dev/spidev0.1'; // Device 0, ChipSelect 1
cSPI_SPEED = 1000000; // Datenrate in Hz
cSPI_BITS = 8; // Datenbits
cSPI_LSBF = 0; // LSB first = -1
cSPI_MODE = cSPI_MODE_0;
type
spi_ioc_transfer = record
tx_buf : uint64; //pointer;
rx_buf : uint64; //pointer; // immer 64-bit
len : uint32; // Anzahl Zeichen
speed : uint32; // Datenrate in Hz
delay : uint16; // Verzögerung CS in usec
bpw : uint8; // Bits per Word
csc : uint8; // CS change
txn : uint8;
rxn : uint8;
pad : uint16;
end;
var
spi : Tspi;
spihnd : longint;
implementation
==
// SPI initialisieren
procedure Tspi.Init();
var
val8 : shortint;
val32 : longint;
begin
try
spihnd := FpOpen(cSPI_DEVICE, O_RdWr);
if spihnd <> -1 then begin
val8 := cSPI_MODE;
FpIOCtl(spihnd, cSPI_WR_MODE, @val8);
val8 := cSPI_BITS;
FpIOCtl(spihnd, cSPI_WR_BITS_PER_WORD, @val8);
val8 := cSPI_LSBF; //-1
FpIOCtl(spihnd, cSPI_WR_LSB_FIRST, @val8);
val32 := cSPI_SPEED;
FpIOCtl(spihnd, cSPI_WR_MAX_SPEED_HZ, @val32);
// FpIOCtl(spihnd, cSPI_RD_MODE, @val8);
// WriteLn('Mode ', IntToHex(val8, 2));
// FpIOCtl(spihnd, cSPI_RD_BITS_PER_WORD, @val8);
// WriteLn('Bits ', val8);
// FpIOCtl(spihnd, cSPI_RD_MAX_SPEED_HZ, @val32);
// WriteLn('Speed ', val32);
end;
finally
end;
end;
// SPI beenden
procedure Tspi.Close();
begin
if spihnd <> -1 then begin
FpClose(spihnd);
end;
end;
// SPI Buffer Read
function Tspi.DataIn(var din; cnt : integer) : integer;
begin
if spihnd <> -1 then begin
DataIn := FpRead(spihnd, din, cnt);
end;
end;
// SPI Buffer Write
function Tspi.DataOut(const dout; cnt : integer) : integer;
begin
if spihnd <> -1 then begin
DataOut := FpWrite(spihnd, dout, cnt);
end;
end;
// SPI Daten senden, empfangen
procedure Tspi.TransferSync(const dout; var din; len : integer);
var
status : integer;
outbuf : array of shortint;
inbuf : array of shortint;
transfer : spi_ioc_transfer;
begin
if len > 0 then begin
SetLength(outbuf, len);
FillByte(outbuf[0], len, 0);
Move(dout, outbuf[0], len);
SetLength(inbuf, len);
FillByte(inbuf[0], len, 0);
FillByte(transfer, SizeOf(transfer), 0);
transfer.tx_buf := uint64(@outbuf[0]);
transfer.rx_buf := uint64(@inbuf[0]);
transfer.len := len;
transfer.delay := 0;
transfer.speed := cSPI_SPEED;
transfer.bpw := cSPI_BITS;
transfer.csc := 0;
try
FpIOCtl(spihnd, $40206B00, @transfer);
finally
Move(inbuf[0], din, len);
end;
end;
end;
// SPI Daten senden ohne Empfang strom
procedure Tspi.TransmitSync(const dout; len : integer);
var
status : integer;
outbuf : array of shortint;
// inbuf : array of shortint;
transfer : spi_ioc_transfer;
begin
if len > 0 then begin
SetLength(outbuf, len);
FillByte(outbuf[0], len, 0);
Move(dout, outbuf[0], len);
// SetLength(inbuf, 1);
// FillByte(inbuf[0], len, 0);
FillByte(transfer, SizeOf(transfer), 0);
transfer.tx_buf := uint64(@outbuf[0]);
transfer.rx_buf := uint64(@outbuf[0]); // gleicher Buffer
transfer.len := len;
transfer.delay := 0;
transfer.speed := cSPI_SPEED;
transfer.bpw := cSPI_BITS;
transfer.csc := 0;
try
FpIOCtl(spihnd, $40206B00, @transfer);
finally
end;
end;
end;
// SPI einzelnes Byte senden, empfangen
function Tspi.FastShift(dout : shortint) : shortint;
var
din : shortint;
transfer : spi_ioc_transfer;
begin
din := 0;
FillByte(transfer, SizeOf(transfer), 0);
transfer.tx_buf := uint64(@dout);
transfer.rx_buf := uint64(@din);
transfer.len := 1;
transfer.delay := 0;
transfer.speed := cSPI_SPEED;
transfer.bpw := cSPI_BITS;
transfer.csc := 0;
try
FpIOCtl(spihnd, $40206B00, @transfer);
finally
FastShift := din;
end;
end;
end.