(*
说明:全志A20的GPIO底层操作封装类。分为两个部分:
1.TGPIOGROUP类,可对寄存器直接操作,单例;
2.TGPIO类,对具体的Pin实现了一些功能的简化。
作者:tjCFeng
邮箱:tjCFeng@163.com
更新日期:2014.12.06
*)

unit GPIO;

{$mode objfpc}{$H+}

interface

uses A20, Clock;

type
  TPort = (PA, PB, PC, PD, PE, PF, PG, PH, PI); //PS:DRAM
  TFun = (Fun0, Fun1, Fun2, Fun3, Fun4, Fun5, Fun6, Fun7); //Fun0:Input; Fun1:Output
  TDrv = (Level0, Level1, Level2, Level3);
  TPull = (PULL_OFF, PULL_UP, PULL_DOWN);

  TGPIOGROUP = class
  private
    FPort: TPort;
    FGPIO_BASE: ^LongWord;
  protected
    FGPIO_CFG: TGROUP4_REG;
    FGPIO_DAT: TGROUP1_REG;
    FGPIO_DRV: TGROUP2_REG;
    FGPIO_PUL: TGROUP2_REG;
  public
    constructor Create(Port: TPort);
    destructor Destroy; override;
  public
    property GPIO_CFG: TGROUP4_REG read FGPIO_CFG;
    property GPIO_DAT: TGROUP1_REG read FGPIO_DAT;
    property GPIO_DRV: TGROUP2_REG read FGPIO_DRV;
    property GPIO_PUL: TGROUP2_REG read FGPIO_PUL;
  end;

  TGPIO = class(TGPIOGROUP)
  private
    FPin: Byte;
    FPinBit: LongWord;

    FPIN_CFG: ^LongWord;
    FPIN_DAT: ^LongWord;
    FPIN_DRV: ^LongWord;
    FPIN_PUL: ^LongWord;
  protected
    procedure SetFun(Fun: TFun);
    procedure SetDrv(Drv: TDrv);
    procedure SetPull(Pull: TPull);
    procedure SetData(Level: Boolean);
    function GetData: Boolean;
  public
    constructor Create(Port: TPort; Pin: Byte);
    procedure Reverse;
  public
    property Fun: TFun write SetFun;
    property Drv: TDrv write SetDrv;
    property Pull: TPull write SetPull;
    property Data: Boolean read GetData write SetData;
  end;

implementation

const
  PIO_BASE = $01C20800;

(*GPIO Group*******************************************************************)
constructor TGPIOGROUP.Create(Port: TPort);
var Base: LongWord;
begin
  inherited Create;

  FPort:= Port;
  FGPIO_BASE:= TA20.Instance.GetMMap(PIO_BASE);
  Base:= LongWord(FGPIO_BASE) + TA20.Instance.BaseOffset(PIO_BASE) + (Ord(FPort) * $24);

  FGPIO_CFG[0]:= Pointer(Base + $00);
  FGPIO_CFG[1]:= Pointer(Base + $04);
  FGPIO_CFG[2]:= Pointer(Base + $08);
  FGPIO_CFG[3]:= Pointer(Base + $0C);
  FGPIO_DAT:= Pointer(Base + $10);
  FGPIO_DRV[0]:= Pointer(Base + $14);
  FGPIO_DRV[1]:= Pointer(Base + $18);
  FGPIO_PUL[0]:= Pointer(Base + $1C);
  FGPIO_PUL[1]:= Pointer(Base + $20);

  TCCU.Instance.CLK_SetGPIO(True);
end;

destructor TGPIOGROUP.Destroy;
begin
  TA20.Instance.FreeMMap(FGPIO_BASE);

  inherited Destroy;
end;

(*GPIO Pin*********************************************************************)
constructor TGPIO.Create(Port: TPort; Pin: Byte);
begin
  inherited Create(Port);

  FPort:= Port;
  FPin:= Pin;
  FPinBit:= ($1 shl FPin);

  FPIN_CFG:= FGPIO_CFG[FPin div 8];
  FPIN_DAT:= FGPIO_DAT;
  FPIN_DRV:= FGPIO_DRV[FPin div 16];
  FPIN_PUL:= FGPIO_PUL[FPin div 16];
end;

procedure TGPIO.SetFun(Fun: TFun);
var PinN: Byte;
begin
  PinN:= (FPin mod 8) * 4;
  FPIN_CFG^:= FPIN_CFG^ and not ($7 shl PinN);
  FPIN_CFG^:= FPIN_CFG^ or (Ord(Fun) shl PinN);
end;

procedure TGPIO.SetDrv(Drv: TDrv);
var PinN: Byte;
begin
  PinN:= (FPin mod 16) * 2;
  FPIN_DRV^:= FPIN_DRV^ and not ($3 shl PinN);
  FPIN_DRV^:= FPIN_DRV^ or (Ord(Drv) shl PinN);
end;

procedure TGPIO.SetPull(Pull: TPull);
var PinN: Byte;
begin
  PinN:= (FPin mod 16) * 2;
  FPIN_PUL^:= FPIN_PUL^ and not ($3 shl PinN);
  FPIN_PUL^:= FPIN_PUL^ or (Ord(Pull) shl PinN);
end;

procedure TGPIO.SetData(Level: Boolean);
begin
  case Level of
  False: FPIN_DAT^:= FPIN_DAT^ and not FPinBit;
  True: FPIN_DAT^:= FPIN_DAT^ or FPinBit;
  end;
end;

function TGPIO.GetData: Boolean;
begin
  Result:= ((FPIN_DAT^ and FPinBit) = FPinBit);
end;

procedure TGPIO.Reverse;
begin
  FPIN_DAT^:= FPIN_DAT^ xor FPinBit;
end;

end.