The Relogix translation

Note: This is a 100% automatic translation, with no human intervention or cleaning-up of the code. Relogix has automatically chosen the function prototypes, has chosen the variable names and types itself, and has placed the assembler comments in the translated source allowing for the re-arrangement of the code flow.




/************************************************************************
*                                                                       *
*       "i2c.c" - Translated from file "i2c.asm"                        *
*                                                                       *
*-----------------------------------------------------------------------*
*                                                                       *
*       Relogix Code Translator Copyright (c) MicroAPL 1990-2017        *
*                   All Rights Reserved Worldwide                       *
*                                                                       *
*************************************************************************
*
*/

/*
*****************************************************************************
*                     Software Implemented I2C Drivers
* These routines allow an 80C51 based microcontroller to drive the I2C bus 
* as a single master. The main program at the end demonstrates writing and 
* reading several types of devices: 
*    PCF8570 256 byte static RAM.
*    PCF8574 8-bit I/O expander.
*    SAA1064 4 digit LED display driver.
*             Written by G.Goodhue, Philips Components-Signetics
*****************************************************************************
*/


#include "rlx8051.h"
#include "i2c.h"

/* Addresses of several I2C devices as connected on the Signetics I2C 
   Evaluation Board.
*/
#define I2CRAM               0x0ae               /* Slave address for PCF8570 RAM chip. */
#define I2CIO                0x4e                /* Slave address for PCF8574 I/O expandor. */
#define I2CLED               0x76                /* Slave address for SAA1064 LED driver. */

/* Prototypes for private routines translated to C */
static void BitDly (void);
static void SCLHigh (void);
static void SendStop (void);
static void SendByte (unsigned char data_byte);
static void GoMaster (void);
static void SendData (unsigned char *data);
static unsigned char RcvByte (void);
static void RcvData (unsigned char *ptr);



/* Global variables */

/* I2C connections. */
Boolean I2CBusy;                                  /* I2C busy flag. */
Boolean NoAck;                                    /* I2C no acknowledge flag. */
Boolean BusFault;                                 /* I2C bus fault flag. */

/* Private file-scope variables */

/*****************************************************************************
                                 Definitions
  ****************************************************************************
   Data storage locations */
static char BitCnt;                               /* Bit counter for I2C routines. */
static char ByteCnt;                              /* Byte counter for I2C routines. */
static unsigned char SlvAdr;                      /* Slave address for I2C routines. */
static unsigned char XmtDat [8];                  /* I2C transmit buffer, 8 bytes max. */
static unsigned char RcvDat [8];                  /* I2C receive buffer, 8 bytes max. */
static unsigned char AltRcv [8];                  /* Alternate I2C receive buffer, 8 bytes max. */


/*
*************************************************************************
* BitDly                                                                *
*************************************************************************
*
* BitDly - insures minimum high and low clock times on I2C bus.
* This routine must be tuned for the actual oscilator frequency used, shown
* here tuned for a 12MHz clock. Note that the CALL instruction that invokes
* BitDly already uses 2 machine cycles.
*/
static void BitDly (void)
{
    _rlx_delay (1);                              /* NOPs to delay 5 microseconds (minus 4 
                                                      machine cycles for CALL and RET). */
}


/*
*************************************************************************
* SCLHigh                                                               *
*************************************************************************
*
* SCLHigh - sends SCL pin high and waits for any clock stretching peripherals.
*/
static void SCLHigh (void)
{
    SCLPIN = 1;                                  /* Set SCL from our end.  */
    while (!SCLPIN)
        ;
}


/*
*************************************************************************
* SendStop                                                              *
*************************************************************************
*
* SendStop - sends an I2C stop, releasing the bus.
*/
static void SendStop (void)
{
    SDAPIN = 0;                                  /* Get SDA ready for stop.  */
    SCLHigh ();                                  /* Set clock for stop.  */
    BitDly ();
    SDAPIN = 1;                                  /* Send I2C stop.  */
    BitDly ();
    I2CBusy = False;                             /* Clear I2C busy status.  */
}


/*
*************************************************************************
* SendByte                                                              *
*************************************************************************
*
* SendByte - sends one byte of data to an I2C slave device.
* Enter with:
*   ACC = data byte to be sent.
*
* Parameters:
*
*    unsigned char data_byte                        [Originally in a; In]
*/
static void SendByte (unsigned char data_byte)
{
    BitCnt = 8;                                  /* Set bit count.  */
    do {
        SDAPIN = (data_byte & (1 << 7)) != 0;    /* Send one data bit. 
                                                     Put data bit on pin. */
        data_byte *= 2;
        SCLHigh ();                              /* Send clock.  */
        BitDly ();
        SCLPIN = 0;
        BitDly ();
    } while (--BitCnt != 0);

    SDAPIN = 1;                                  /* Release data line for acknowledge.  */
    SCLHigh ();                                  /* Send clock for acknowledge.  */
    BitDly ();
    if (SDAPIN)
        NoAck = True;                            /* Set status for no acknowledge.  */
    SCLPIN = 0;                                  /* Finish acknowledge bit.  */
    BitDly ();
}


/*
*************************************************************************
* GoMaster                                                              *
*************************************************************************
*
* GoMaster - sends an I2C start and slave address.
* Enter with:
*   SlvAdr = slave address.
*/
static void GoMaster (void)
{
    I2CBusy = True;                              /* Indicate that I2C frame is in progress.  */
    NoAck = False;                               /* Clear error status flags.  */

    if (SCLPIN && SDAPIN) {
        BusFault = False;
        SDAPIN = 0;                              /* Begin I2C start.  */
        BitDly ();
        SCLPIN = 0;
        BitDly ();                               /* Complete I2C start.  */
        SendByte (SlvAdr);                       /* Get slave address. 
                                                     Send slave address. */

    } else
        BusFault = True;                         /* Set fault status  */

}


/*
*************************************************************************
* SendData                                                              *
*************************************************************************
*
* SendData - sends one or more bytes of data to an I2C slave device.
* Enter with:
*   ByteCnt = count of bytes to be sent.
*   SlvAdr  = slave address.
*   @R0     = data to be sent (the first data byte will be the
*             subaddress, if the I2C device expects one).
*
* Parameters:
*
*    unsigned char *data                            [Originally in r0; In]
*/
static void SendData (unsigned char *data)
{
    GoMaster ();                                 /* Acquire bus and send slave address.  */
    if (!NoAck) {
        do {
            SendByte (*data);                    /* Get data byte from buffer. 
                                                     Send next data byte. */
            data++;                              /* Advance buffer pointer.  */
        } while (!NoAck && --ByteCnt != 0);
    }
    SendStop ();                                 /* Done, send an I2C stop.  */
}


/*
*************************************************************************
* RcvByte                                                               *
*************************************************************************
*
* RcvByte - receives one byte of data from an I2C slave device.
* Returns:
*   ACC = data byte received.
*
* Parameters:
*
*
* Result:
*
*    unsigned char                                  [Originally in a]
*/
static unsigned char RcvByte (void)
{
    unsigned char val;                           /* [Originally in a] */

    BitCnt = 8;                                  /* Set bit count.  */
    val = 0;
    do {
        SCLHigh ();                              /* Read one data bit.  */
        BitDly ();
        val = (val * 2) | (SDAPIN ? 1 : 0);      /* Get data bit from pin. 
                                                     Rotate bit into result byte. */
        SCLPIN = 0;
        BitDly ();
    } while (--BitCnt != 0);

    SDAPIN = (ByteCnt == 1) ? 1 : 0;
    SCLHigh ();                                  /* Send acknowledge clock.  */
    BitDly ();
    SCLPIN = 0;
    SDAPIN = 1;                                  /* Clear acknowledge bit.  */
    BitDly ();
    return val;
}


/*
*************************************************************************
* RcvData                                                               *
*************************************************************************
*
* RcvData - receives sends one or more bytes of data from an I2C slave device.
* Enter with:
*   ByteCnt = count of bytes to be sent.
*   SlvAdr  = slave address.
* Returns:
*   @R0     = data received.
* Note: to receive with a subaddress, use SendData to set the subaddress
*   first (no provision for repeated start).
*
* Parameters:
*
*    unsigned char *ptr                             [Originally in r0; In]
*/
static void RcvData (unsigned char *ptr)
{
    SlvAdr++;                                    /* Set for READ of slave.  */
    GoMaster ();                                 /* Acquire bus and send slave address.  */
    if (!NoAck) {
        do {
            *ptr++ = RcvByte ();                 /* Recieve next data byte. 
                                                     Save data byte in buffer. */
        } while (--ByteCnt != 0);
    }
    SendStop ();                                 /* Done, send an I2C stop.  */
}


/*
*************************************************************************
* Reset                                                                 *
*************************************************************************
*
*
*                               Main Program
*
*/
void Reset (void)
{
    XmtDat [0] = 0;                              /* Initialize transmit data area.  */
    XmtDat [1] = 0x37;
    XmtDat [2] = 0x0aa;
    XmtDat [3] = 0x055;
    XmtDat [4] = 0x33;
    XmtDat [5] = 0x0cc;
    XmtDat [6] = 0x0ff;
    XmtDat [7] = 0x0bb;
    while (True) {
        SlvAdr = I2CIO;                          /* Write data to PCF8574 I/O expandor.  */
        ByteCnt = 1;                             /* Send one data byte.  */
        SendData (&XmtDat [2]);                  /* Start of data.  */
        SlvAdr = I2CIO;                          /* Read back data from PCF8574 I/O expandor.  */
        ByteCnt = 1;                             /* Read one data byte.  */
        RcvData (AltRcv);                        /* Start of data.  */
        XmtDat [2]++;                            /* Advance data to next value.  */
        SlvAdr = I2CLED;                         /* Write data to SAA1064 LED driver.  */
        ByteCnt = 6;                             /* Send 6 bytes (subaddress, control, data).  */
        SendData (XmtDat);                       /* Start of data.  */
        SlvAdr = I2CRAM;                         /* Write data to PCF8570 RAM.  */
        ByteCnt = 8;                             /* Send 8 bytes (subaddress + 7 data bytes).  */
        SendData (XmtDat);                       /* Start of data.  */
        SlvAdr = I2CRAM;                         /* Write subaddress to PCF8570 RAM.  */
        ByteCnt = 1;                             /* Send one byte (subaddress).  */
        SendData (XmtDat);                       /* Start of data.  */
        SlvAdr = I2CRAM;                         /* Read back data from PCF8570 RAM.  */
        ByteCnt = 7;                             /* Read 7 data bytes.  */
        RcvData (RcvDat);                        /* Start of data.  */
    }
}