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

Files at this revision

API Documentation at this revision

Comitter:
DavidGilesHitex
Date:
Tue Nov 23 10:59:14 2010 +0000
Commit message:

Changed in this revision

Header/PCA9675.h Show annotated file Show diff for this revision Revisions of this file
Header/misra_types.h Show annotated file Show diff for this revision Revisions of this file
Source/PCA9675.cpp Show annotated file Show diff for this revision Revisions of this file
Source/main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Header/PCA9675.h	Tue Nov 23 10:59:14 2010 +0000
@@ -0,0 +1,46 @@
+#include "mbed.h"
+
+#ifndef PCA9675__
+#define PCA9675__
+#endif
+
+/* Define a class for PCA9675 */
+class PCA9675
+    {
+        /* Private members first */
+        private:
+            uint8_t My_Lcoal_Slave_Address;
+            uint8_t My_Local_Port0_Direction;
+            uint8_t My_Local_Port1_Direction;
+            sint32_t reset();                                                                       /* Reset the device using a general call */
+            I2C *My_Local_I2C;                                                                      /* make use of the existing I2C class for i2C calls */
+            
+        /* Public members next */
+        public: 
+            PCA9675(I2C *Selected_I2C_Channel, uint8_t Slave_Address);                              /* Constructor - create with the slave address */
+            ~PCA9675();                                                                             /* Destructor */
+            sint32_t init(uint8_t port0_Direction, uint8_t port1_Direction);                        /* Reset the device and setup the IO direction */
+            sint32_t write_data(uint8_t port0_payload, uint8_t port1_payload);                      /* Write two bytes of data to the device */
+            sint32_t read_data(uint8_t *read_port0, uint8_t *read_port1);                           /* Read two bytes from the device */
+            sint32_t read_device_ID(uint8_t *manufacturer, uint16_t *part_ident, uint8_t *die_revision);
+            uint8_t read_slave_address();                                                           /* Read the configured slave address */
+
+
+            enum PCA9675_Defines
+                {
+                eI2C_ACK = 0,
+                ePCA9675_RESET_COMMAND = 6,
+                ePCA9675_RESET_ADDRESS = 0,
+                ePCA9675_PORT0 = 0,
+                ePCA9675_PORT1 = 1,
+                eI2C_REPEATED_START = 1,
+                eI2C_NO_REPEATED_START = 0                
+                };
+
+
+    };
+        
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Header/misra_types.h	Tue Nov 23 10:59:14 2010 +0000
@@ -0,0 +1,32 @@
+/* Hitex Standard Header File */
+/* Types As Recommended By MISRA */
+
+
+
+/* Bytes (8bit length) */
+typedef unsigned char uint8_t;
+typedef char sint8_t;
+
+/* Half Words (16bit lengths) */
+typedef unsigned short uint16_t;
+typedef short sint16_t;
+
+/* Words (32bit lengths) */
+/* Also int */
+typedef unsigned int uint32_t;
+typedef long sint32_t;
+
+/* Double Words */
+/* Also long long and long double */
+typedef unsigned long long uint64_t;
+typedef long long sint64_t;
+
+
+/*
+ Constants should use the following suffixes also 
+
+u - Unsigned
+f - floating
+L - Long double (64bit)
+
+*/
--- /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;
+    }                                           
+        
+        
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/main.cpp	Tue Nov 23 10:59:14 2010 +0000
@@ -0,0 +1,91 @@
+/* PCA9675 Device Driver C++ Example */
+/* ********************************* */
+
+#include "mbed.h"
+#include "misra_types.h"                         /* MISRA Types */
+#include "PCA9675.h"
+
+
+#define PCA9675_BASE_BOARD_SLAVE_ADDRESS 0x20
+
+
+/* I2C Interface */
+/* Create a master I2C bus called CNTRL_i2C using pins 9 and 10 for SDA, & SCL  respectively */
+/* This I2C bus can be used fr many peripherals and not just the PCA9675 */
+I2C CNTRL_i2c(p9, p10);                         
+
+/* Configure the USB as a virtual communications port */
+Serial pc(USBTX, USBRX);
+
+/* Create a global object of PCA96755 class called BaseBoardLatch */
+/* this device will use CNTRL_i2c bus and has a slave address of PCA9675_BASE_BOARD_SLAVE_ADDRESS*/
+PCA9675 BaseBoardLatch(&CNTRL_i2c, PCA9675_BASE_BOARD_SLAVE_ADDRESS);       
+                                                                            
+
+int main() 
+    {
+        uint8_t port0_payload = 0;
+        uint8_t port1_payload = 0;
+        uint8_t manufacturer = 0;
+        uint16_t part_ident = 0;
+        uint8_t die_revision = 0;
+        uint8_t MySlaveAddress = 0;
+        sint32_t Ack_Status = 0;
+
+        pc.baud(115000);                        /* Baud rate should be 115k baud */
+        pc.format(8,Serial::None,1);            /* format is 8 data bits, no stop bit, no parity */
+        pc.printf("\n\n\n\n\n\n\n\rWelcome to the I2C PCA9675 Driver Test Routines for mbed\n\r\n");
+        
+        CNTRL_i2c.frequency(400000);           /* Set the I2C to be 400kHz */
+        
+        /* Read the PCA9575 device ID */
+        pc.printf("Reading the device ID\n\r");
+        Ack_Status = BaseBoardLatch.read_device_ID(&manufacturer, &part_ident, &die_revision);
+        pc.printf("Read ID: Ack status = ");
+        if (Ack_Status ==  BaseBoardLatch.eI2C_ACK) pc.printf("ACK\n\r");
+        else pc.printf ("NACK\n\r");
+        pc.printf("The stored identification for this device is:\n\r");
+        pc.printf("  * Manufacturer Code = 0x%.2x\n\r",  manufacturer); 
+        pc.printf("  * Part Idenfification = 0x%.4x\n\r", part_ident);
+        pc.printf("  * Die Revision = 0x%.1x\n\r", die_revision);
+        
+
+        /* Use this code for output */
+
+        /* Setup the I/O direction : for each bit 1=input and 0=output */
+        /* Order is Port0 and Port1 */
+        pc.printf("\nSetting the device for quasi output mode\n\r");
+        Ack_Status = BaseBoardLatch.init(0x00, 0x00);             
+        pc.printf("Initialise: Ack status = ");
+        if (Ack_Status == BaseBoardLatch.eI2C_ACK) pc.printf("ACK\n\r");
+        else pc.printf ("NACK\n\r");
+        
+        pc.printf("Writing data to the latch\n\r");
+        Ack_Status = BaseBoardLatch.write_data(port0_payload, port1_payload);       /* Write two bytes of data to the device */
+        pc.printf("Write data: Ack status = ");
+        if (Ack_Status == BaseBoardLatch.eI2C_ACK) pc.printf("ACK\n\r");
+        else pc.printf ("NACK\n\r");
+   
+                
+        /* Use this code for input */
+        
+        /* Setup the I/O direction : for each bit 1=input and 0=output */
+        /* Order is Port0 and Port1 */
+        pc.printf("\nSetting the device for quasi input mode\n\r");
+        Ack_Status = BaseBoardLatch.init(0xff, 0xff);
+        pc.printf("Initialise: Ack status = ");
+        if (Ack_Status == BaseBoardLatch.eI2C_ACK) pc.printf("ACK\n\r");
+        else pc.printf ("NACK\n\r");
+        
+        Ack_Status = BaseBoardLatch.read_data(&port0_payload, &port1_payload);       /* Read two bytes from the device */
+        pc.printf("Read data: Ack status = ", Ack_Status);
+        if (Ack_Status == BaseBoardLatch.eI2C_ACK) pc.printf("ACK\n\r");
+        else pc.printf ("NACK\n\r");
+        pc.printf("Port0 = 0x%.2x, Port1 = 0x%.2x\n\r", port0_payload, port1_payload);
+
+        
+        /* Read back the slave address of the PCA9675 object if we need to recall it */
+        MySlaveAddress = BaseBoardLatch.read_slave_address();
+        pc.printf("\nThe 7 bit Slave address: is = 0x%.2x\n\r", MySlaveAddress);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Nov 23 10:59:14 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/e2ac27c8e93e