This software drives a PCA9675 device via an I2C bus. Included functions allow you to read the device ID, set the IO direction, and read and write from the device.

Dependencies:   mbed

Source/PCA9675.cpp

Committer:
DavidGilesHitex
Date:
2010-11-23
Revision:
0:3331b5950572

File content as of revision 0:3331b5950572:

/* C++ Source Code for PCA9675 I2C 16bit IO latch */
/* ********************************************** */


#include "misra_types.h"
#include "mbed.h"
#include "PCA9675.h"




/* Constructor */
PCA9675::PCA9675(I2C *Selected_I2C_Channel, uint8_t Slave_Address)
    {
        My_Local_I2C = Selected_I2C_Channel;
        My_Lcoal_Slave_Address = Slave_Address;
    }

/* Destructor */
PCA9675::~PCA9675()
    {
    }
    


/* Setup and configure the I/O latch */
sint32_t PCA9675::init(uint8_t Port0_Direction, uint8_t Port1_Direction)
    {
        sint32_t Ack_Status = eI2C_ACK;

        Ack_Status = reset();                                                   /* Reset the device */
        My_Local_Port0_Direction = Port0_Direction;                             /* Keep a copy of the port0 direction */
        My_Local_Port1_Direction = Port1_Direction;                             /* Keep a copy of the port1 direction */
        
        if (Ack_Status == eI2C_ACK)
            {
                Ack_Status = write_data(Port0_Direction, Port1_Direction);      /* This configures the I/O direction: each bit: 0=output, 1=inout  */
            }
             
        return Ack_Status;
    }        

    


/* Reset the device */                
sint32_t PCA9675::reset()
    {
        sint32_t Ack_Status = eI2C_ACK;
        sint8_t reset_command = ePCA9675_RESET_COMMAND;                         /* Reset command following a general call, address 0 will reset the device */

        Ack_Status = My_Local_I2C -> write(ePCA9675_RESET_ADDRESS << 1, &reset_command, 1, eI2C_NO_REPEATED_START); 
                                                                                                
        return Ack_Status;                                                                                        
    }                                    


/* Write two byte of data to the device */
sint32_t PCA9675::write_data(uint8_t port0_payload, uint8_t port1_payload)
    {
        sint32_t Ack_Status = eI2C_ACK;
        sint8_t tx_array[2];                                                   /* Local array of data to be transmitted */
        
        /* If we try and write a 0/1 to a pin that is designated an input we must force the state to a 1(input) */
        /* as the device is quasi birectional */
        /* This is to avoid turning the pin from a designated input into an output by mistake */
        /* If the pin is designated as input and we have logic 1 on the input we and indvertantly write a 0 to it */
        /* then we will have a large current flow input the pin */
        /* Hence the 'or' block below prevents unwanted damage to the pin */
        /* Quasi direction is: 1 = input, 0 = output */
        port0_payload = (port0_payload | My_Local_Port0_Direction);
        port0_payload = (port1_payload | My_Local_Port1_Direction);
        
        tx_array[ePCA9675_PORT0] = port0_payload;                              /* First is for Port 0 */
        tx_array[ePCA9675_PORT1] = port1_payload;                              /* Second is for Port 1 */
 
        Ack_Status = My_Local_I2C -> write(My_Lcoal_Slave_Address << 1, tx_array, 2, eI2C_NO_REPEATED_START);  
        return Ack_Status;
    }


/* Read two bytes from the device */
sint32_t PCA9675::read_data(uint8_t *read_port0, uint8_t *read_port1)
    {
        sint32_t Ack_Status = eI2C_ACK;
        sint8_t rx_array[2];                                                   /* Local reception array */

        Ack_Status = My_Local_I2C -> read(My_Lcoal_Slave_Address << 1, rx_array, 2, eI2C_NO_REPEATED_START); 

        *read_port0 = rx_array[ePCA9675_PORT0];                               /* transfer data back to pointer */
        *read_port1 = rx_array[ePCA9675_PORT1];                               /* transfer data back to pointer */
        return Ack_Status;
    }        


/* Read the device ID */
sint32_t PCA9675::read_device_ID(uint8_t *manufacturer, uint16_t *part_ident, uint8_t *die_revision)

    {
        sint32_t Ack_Status = eI2C_ACK;
        sint8_t rx_array[3] = {0,0,0};
        uint32_t temp_value = 0;
        sint8_t tx_array = (My_Lcoal_Slave_Address << 1);

      
        Ack_Status = My_Local_I2C -> write(0xF8, &tx_array, 1, eI2C_REPEATED_START);
        Ack_Status = My_Local_I2C ->  read(0xF9, rx_array,  3, eI2C_NO_REPEATED_START);            
      
        temp_value = rx_array[0];
        temp_value = (temp_value << 8);
        
        temp_value = (temp_value | rx_array[1]);
        temp_value = (temp_value << 8);
        
        temp_value = (temp_value | rx_array[2]);
        
        
        *die_revision = (uint8_t) (temp_value & 0x00000003);                            /* 3 LSB bits are die revision */
        temp_value = (temp_value >> 3);
        
        *part_ident = (uint16_t) (temp_value & 0x00001FFF);                               /* Next 13 bits are part identification */
        temp_value = (temp_value >> 13);
        
        *manufacturer = (uint8_t) (temp_value & 0x000000FF);                               /* Next 8 bits are manufacturers name */

        return Ack_Status;
    }        




/* Read the configured slave address */
uint8_t PCA9675::read_slave_address()
    {
        return My_Lcoal_Slave_Address;
    }