Raspberry Pi - SPI/de

From Lazarus wiki
Revision as of 23:00, 21 October 2017 by Timm Thaler (talk | contribs) (Created page with "==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 di...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

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.