//------------------------------------------------------
// DS1624 Temperature Sensor: XJEase device file
// DS1624_THERMOMETER.xje Revision: 1.12
// (c)2001-2007 XJTAG Limited
//
// Disclaimer: XJTAG makes no guarantees whatsoever
// about this code.  You use it at your own risk ...
//
// This code requires XJTAG version 1.4 or later.
//------------------------------------------------------

DEVICE NAME := "DS1624"
  // Pin description
  PINS
    SCL := 2;
    SDA := 1;
    ADD := 7, 6, 5;
  END;

  DISABLE DEVICE
    SCL := Z;
    SDA := Z;
  END;

  TEST COVERAGE
    SCL := OPEN HI LO;
    SDA := OPEN HI LO;
  END;
END;

//------------------------------------------------------
// Constants
//------------------------------------------------------

CONST INT DEVICE_ADDRESS        WIDTH 8 := 0x90;

CONST INT COMMAND_READ_TEMP     WIDTH 8 := 0xaa;
CONST INT COMMAND_START_CONVERT WIDTH 8 := 0xee;
CONST INT COMMAND_STOP_CONVERT  WIDTH 8 := 0x22;
CONST INT COMMAND_ACCESS_MEMORY WIDTH 8 := 0x17;
CONST INT COMMAND_ACCESS_CONFIG WIDTH 8 := 0xac;

CONST INT EXIT_ON_IIC_ERROR := TRUE;
CONST INT OK := 0;

//------------------------------------------------------
// Prints out the current temperature reading.
// 'result' is always OK (0).
Test()(INT result)
//------------------------------------------------------

  INT temp WIDTH 16;

  PRINT("Testing DS1624 temperature sensor ", DEVICE_REF, "\n");

  I2C_Write(COMMAND_START_CONVERT, DEVICE_ADDRESS);
  I2C_Read(COMMAND_READ_TEMP, DEVICE_ADDRESS)(temp);
  PRINT("\t Local temperature is ", (temp[15..3] * 3125)/100000, " degC\n");

  result := OK;

END;

//------------------------------------------------------------------
// Generic I2C Code
// (c)2002-2007 XJTAG Limited
//
// Access is through the following functions:
//   I2C_FindDevice - prints out the I2C address of all devices that acknowledge.
//   I2C_Write - transmits a single byte to the given address.
//   I2C_Read - reads a single byte from the given address.
// N.B. This code assumes that we can't exceed the IIC clock speed.
//
// Disclaimer: XJTAG makes no guarantees whatsoever
// about this code.  You use it at your own risk ...
//------------------------------------------------------------------

//------------------------------------------------------------------
I2C_FindDevice()()
//------------------------------------------------------------------

  INT i,j := 0;
  INT ack;

  FOR i := 0 TO 128
    I2C_Start();
    I2C_Transmit(j)(ack);
    IF (ack = 0) THEN
      PRINT("IIC device found at address ", j, " HEX 0x", HEX(j), "\n");
    END;
    I2C_Stop();
    j := j + 2;
  END;

END;

//------------------------------------------------------------------
// Write one byte, including IIC start and stop.
I2C_Write(INT byteAddress, INT deviceAddress)()
//------------------------------------------------------------------

  INT ack WIDTH 1;

  I2C_Start();
  I2C_Transmit(deviceAddress)(ack);

  IF (ack = 1) THEN
    I2C_Stop();
    I2C_Start();
    I2C_Transmit(deviceAddress)(ack);
    IF (ack = 1) THEN
      PRINT("I2C_Write Error: Interface failed to acknowledge device address.\n");
      IF EXIT_ON_IIC_ERROR THEN EXIT; END;
    END;
  END;

  I2C_Transmit(byteAddress)(ack);
  IF (ack = 1) THEN
    PRINT("I2C_Write Error: Interface failed to acknowledge byteL address.\n");
    IF EXIT_ON_IIC_ERROR THEN EXIT; END;
  END;

  I2C_Stop();

END;

//------------------------------------------------------------------
// Read one byte, including IIC start and stop.
I2C_Read(INT byteAddress, INT deviceAddress)(INT byteRead)
//------------------------------------------------------------------

  INT ack;
  INT d1 WIDTH 8, d2 WIDTH 8;

  I2C_Start();
  I2C_Transmit(deviceAddress)(ack);
  IF (ack = 1) THEN
    I2C_Stop();
    I2C_Start();
    I2C_Transmit(deviceAddress)(ack);
    IF (ack = 1) THEN
      PRINT("I2C_Read Error: Interface failed to acknowledge device address.\n");
      IF EXIT_ON_IIC_ERROR THEN EXIT; END;
    END;
  END;

  // Transmit address to read from.
  I2C_Transmit(byteAddress)(ack);
  IF (ack = 1) THEN
    PRINT("I2C_Read Error: Interface failed to acknowledge byteL address.\n");
    IF EXIT_ON_IIC_ERROR THEN EXIT; END;
  END;

  // Now terminate write operation and do a read.
  I2C_Start();

  // Transmit address to read from.
  I2C_Transmit(deviceAddress | 1)(ack); // Bottom bit denotes read.

  IF (ack = 1) THEN
    PRINT("I2C_Read Error: Slave failed to ack read access.\n");
    IF EXIT_ON_IIC_ERROR THEN EXIT; END;
  END;

  // Read from address and ack.
  I2C_Receive(0)(d1);
  I2C_Receive(1)(d2);
  byteRead := d1[7..0] : d2[7..0];

  I2C_Stop();

END;

//------------------------------------------------------------------
// Transmit 8 bits and check for an ACK.
I2C_Transmit(INT byte)(INT ack)
//------------------------------------------------------------------

  INT i;

  FOR i := 0 FOR 8
    I2C_WriteBit(byte[7 - i]);
  END;

  I2C_ReadBit()(ack);

END;

//------------------------------------------------------------------
// Read 8 bits and send an ACK (or not).
I2C_Receive(INT ack)(INT byte WIDTH 8)
//------------------------------------------------------------------

  INT bit WIDTH 1;
  INT i;

  // Clear the byte so that top bits don't become set.
  byte := 0;

  FOR i := 0 FOR 8
    I2C_ReadBit()(bit);
    byte := (byte << 1) | bit;
  END;

  I2C_WriteBit(ack)();

END;

//------------------------------------------------------------------
// I2C start condition is high to low transition on SDA while SCK is high.
I2C_Start()()
//------------------------------------------------------------------

  INT c WIDTH 1, d WIDTH 1;

  // Check whether the bus is free.
  SET c := SCL, d := SDA;
  DO WHILE (~c || ~d)
    SET c := SCL, d := SDA;
  END;

  SET SDA := 0;

  // Set clock low ready for first data bit.
  SET SCL := 0;

END;

//------------------------------------------------------------------
// I2C stop condition is low to high transition on SDA while SCK is high.
I2C_Stop()()
//------------------------------------------------------------------

  SET SDA := 0;
  SET SCL := I;
  SET SDA := I;
END;

//------------------------------------------------------------------
// Read one bit over IIC.
I2C_ReadBit()(INT bit)
//------------------------------------------------------------------

  SET SCL := I, SDA := I;
  SET SCL := 0, bit := SDA;  // Get data at end of cycle.

END;

//------------------------------------------------------------------
// Send one bit over IIC.
I2C_WriteBit(INT bit)()
//------------------------------------------------------------------

  IF (bit[0]) THEN
    SET SDA := I;
  ELSE
    SET SDA := 0;
  END;

  // Ensure that the data is stable during the high period.
  SET SCL := I;
  SET SCL := 0;

END;