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.
Diff: Source/PCA9675.cpp
- Revision:
- 0:3331b5950572
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/PCA9675.cpp Tue Nov 23 10:59:14 2010 +0000 @@ -0,0 +1,139 @@ +/* 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; + } + + +