Unit AVRTWIRS; 
||| Extension of the AVRco TWI Master with the Repeated Start function 
||| 
||| Udo Purwin 
||| Version 1.00 initial Release 
||| 07.03.2023 
||| 

interface
  //Reads data from the client with a word as command and Repeated Start 
  function TWIInpRSWP(SlaveAdr : Byte; Command : Word; Data : Pointer; Size : Word) : Boolean; 
  //Reads data from the client with a Byte as command and Repeated Start 
  function TWIInpRSBP(SlaveAdr : Byte; Command : Byte; Data : Pointer; Size : Word) : Boolean; 
  
implementation

const
  TWINT : Byte = 7; 
  TWEA  : Byte = 6; 
  TWSTA : Byte = 5; 
  TWSTO : Byte = 4; 
  TWWC  : Byte = 3; 
  TWEN  : Byte = 2; 
  TWIE  : Byte = 0; 
{--------------------------------------------------------------} 
{$IDATA}
var
  TWITimeout       : SysTimer8; 
Const
  _TWITimeOutms    : Word = 50; 
{--------------------------------------------------------------} 
{ functions } 
  
Function TWI_start : Boolean; 
begin
//Clear TWI INT, Start and Enable TWI 
  TWCR := (1 SHL TWINT) OR (1 SHL TWSTA) or (1 SHL TWEN); 
//Start transmitted? 
  Repeat
    if isSysTimerZero(TWITimeout) then    //TimeOut? Abbort! 
      Return(False); 
    endif; 
  Until Bit(TWCR, TWINT); 
//Check AKN 
  Repeat
    if isSysTimerZero(TWITimeout) then    //TimeOut? Abbort! 
      Return(False); 
    endif; 
  Until ((TWSR AND $F8) = $08) OR ((TWSR AND $F8) = $10); 
  Return(True); 
end; 

Function TWI_stop : Boolean; 
begin
//Clear TWI INT, Stop and Enable TWI 
  TWCR : = (1 SHL TWINT) OR (1 SHL TWEN) OR (1 SHL TWSTO); 
// Stop transmitted? 
  Repeat
    if isSysTimerZero(TWITimeout) then    //TimeOut? Abbort! 
      Return(False); 
    endif; 
  Until Bit(TWCR, TWSTO); 
  Return(True); 
end; 

Function TWI_write_address(SlaveAdr : Byte; AdrWrite : Boolean) : Boolean; 
begin
  if AdrWrite then 
    SlaveAdr := (SlaveAdr SHL 1); 
  else 
    SlaveAdr := (SlaveAdr SHL 1) OR $01; 
  endif; 
  TWDR := SlaveAdr; 
  //Clear TWI INT, Enable TWI 
  TWCR := (1 SHL TWINT) OR (1 SHL TWEN); 
//TWDR transmitted? 
  Repeat
    if isSysTimerZero(TWITimeout) then    //TimeOut? Abbort! 
      Return(False); 
    endif; 
  Until Bit(TWCR, TWINT); 
  Repeat
    if isSysTimerZero(TWITimeout) then    //TimeOut? Abbort! 
      Return(False); 
    endif; 
  Until ((TWSR AND $F8) = $18) OR ((TWSR AND $F8) = $40); 
  Return(True); 
end; 

Function TWI_write_data(Data : Byte) : Boolean; 
begin
  TWDR := Data; 
  //Clear TWI INT, Enable TWI 
  TWCR := (1 SHL TWINT) OR (1 SHL TWEN); 
 //TWDR transmitted? 
  Repeat
    if isSysTimerZero(TWITimeout) then    //TimeOut? Abbort! 
      Return(False); 
    endif; 
  Until Bit(TWCR, TWINT); 
 //Check AKN 
  Repeat
    if isSysTimerZero(TWITimeout) then    //TimeOut? Abbort! 
      Return(False); 
    endif; 
  Until (TWSR AND $F8) = $28; 
  Return(True); 
end; 

Function TWI_read_data(Data : Pointer; LastByte : Boolean) : Boolean; 
begin
 //Clear TWI INT, Enable TWI 
  If Not LastByte then 
    TWCR := (1 SHL TWINT) OR (1 SHL TWEN) OR (1 SHL TWEA); 
  else 
    TWCR := (1 SHL TWINT) OR (1 SHL TWEN); 
  endif; 
//TWDR received? 
  Repeat
    if isSysTimerZero(TWITimeout) then    //TimeOut? Abbort! 
      Return(False); 
    endif; 
  Until Bit(TWCR, TWINT); 
  Data^ := TWDR; 
//Check AKN 
  Repeat
    if isSysTimerZero(TWITimeout) then    //TimeOut? Abbort! 
      Return(False); 
    endif; 
  Until ((TWSR AND $F8) = $50) OR ((TWSR AND $F8) = $58); 
  Return(True); 
end; 


//Reads data from the client with a word as command and Repeated Start 
function TWIInpRSWP(SlaveAdr : Byte; Command : Word; Data : Pointer; Size : Word) : Boolean; 
Var
  _idx  : Word; 
begin
  SetSysTimerM(TWITimeout, _TWITimeOutms); 
  IF NOT TWI_start then 
    Return(False); 
  endif; 
  IF NOT TWI_write_address(SlaveAdr, True) then 
    Return(False); 
  endif; 
  TWI_write_data(Hi(Command)); 
  TWI_write_data(Lo(Command)); 
  //Repeated Start 
  IF NOT TWI_start then 
    Return(False); 
  endif; 
  IF NOT TWI_write_address(SlaveAdr, False) then 
    Return(False); 
  endif; 
  For _idx := 1 To Size - 1 do 
    TWI_read_data(Data, False); 
    inc(Data); 
  endfor; 
  //ReadLastByte with NACK 
  TWI_read_data(Data, True); 
  IF NOT TWI_stop then 
    Return(False); 
  endif; 
  Return(True); 
end; 


//Reads data from the client with a Byte as command and Repeated Start 
function TWIInpRSBP(SlaveAdr : Byte; Command : Byte; Data : Pointer; Size : Word) : Boolean; 
Var
  _idx  : Word; 
begin
  SetSysTimerM(TWITimeout, _TWITimeOutms); 
  IF NOT TWI_start then 
    Return(False); 
  endif; 
  IF NOT TWI_write_address(SlaveAdr, True) then 
    Return(False); 
  endif; 
  TWI_write_data(Command); 
  //Repeated Start 
  IF NOT TWI_start then 
    Return(False); 
  endif; 
  IF NOT TWI_write_address(SlaveAdr, False) then 
    Return(False); 
  endif; 
  For _idx := 1 To Size - 1 do 
    TWI_read_data(Data, False); 
    inc(Data); 
  endfor; 
  //ReadLastByte with NACK 
  TWI_read_data(Data, True); 
  IF NOT TWI_stop then 
    Return(False); 
  endif; 
  Return(True); 
end; 

initialization
end AVRTWIRS.

