mini board PCU9669 (and PCA9665) sample code

Dependencies:   mbed PCU9669 utility PCA9665 I2C_slaves parallel_bus

Fork of mini_board_PCU9669_old by InetrfaceProducts NXP

Sample code for PCU9669 (PCU9661, PCA9663, PCA9661 and PCA9665) evaluation board.

PCU9669 evaluation board: Mini board PCU9669
User manual is available -> http://www.nxp.com/documents/user_manual/UM10580.pdf

Revision:
8:6120bbbe3636
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mini_board_libs/PCA9665/PCA9665_access.c	Wed Mar 28 04:32:50 2012 +0000
@@ -0,0 +1,414 @@
+/** A sample code for "mini board PCU9669/PCA9665"
+ *
+ *  @author  Akifumi (Tedd) OKANO, NXP Semiconductors
+ *  @version 1.0
+ *  @date    26-Mar-2012
+ *
+ *  Released under the MIT License: http://mbed.org/license/mit
+ *
+ *  An operation sample of PCU9669/PCA9665 I2C bus controller.
+ *  The mbed accesses the bus controller's parallel port (8/2 bit address and 8 bit data) by bit-banging.
+ *  The bit-banging is poerformed by PortInOut function of mbed library.
+ *
+ *    To make the code porting easier, all codes are partitioned into layers to abstract other parts.
+ *    The mbed specific parts are concentrated in lowest layer: "hardware_abs.*".
+ *    This module may need to be modified for the porting.
+ *
+ *    All other upper layers are writen in standard-C.
+ *
+ *    base code is written from 05-Sep-2011 to 09-Sep-2011.
+ *    And demo code has been build on 11-Sep-2011.
+ *    Debug and code adjustment has been done on 08-Sep-2011.
+ *    Small sanitization for main.cpp. All mbed related codes are moved in to "hardware_abs.*". 13-Oct-2011
+ *    hardware_abs are moved into parallel_bus library folder, 3 LED driver operation sample 13-Feb.-2012
+ *    PCU9669 and PCA9665 codes are packed in a project 14-Feb-2012. 
+ *    
+ *    Before builidng the code, please edit the file mini_board_PCU9669/config.h
+ *    Un-comment the target name what you want to target. 
+ */
+
+#include "PCA9665_access.h"
+#include "hardware_abs.h"
+
+#define     BUS_CONTINUE            0
+#define     BUS_STOP                1
+#define     BUS_RELEASE             2
+
+typedef enum {
+    I2CSTA  = 0x0,
+    INDPTR  = 0x0,
+    I2CDAT,
+    INDIRECT,
+    I2CCON
+}
+pca9665_direct_registers;
+
+typedef enum {
+    I2CCOUNT,
+    I2CADR,
+    I2CSCLL,
+    I2CSCLH,
+    I2CTO,
+    I2CPRESET,
+    I2CMODE
+}
+pca9665_indirect_registers;
+
+typedef enum {
+    ILLEGAL_START_STOP              = 0x00,
+    MASTER_START_TXed               = 0x08,
+    MASTER_RESTART_TXed             = 0x10,
+    MASTER_SLA_W_ACK                = 0x18,
+    MASTER_SLA_W_NAK                = 0x20,
+    MASTER_DATA_W_ACK               = 0x28,
+    MASTER_DATA_W_NAK               = 0x30,
+    MASTER_ARB_LOST                 = 0x38,
+    MASTER_SLA_R_ACK                = 0x40,
+    MASTER_SLA_R_NAK                = 0x48,
+    MASTER_DATA_R_ACK               = 0x50,
+    MASTER_DATA_R_NAK               = 0x58,
+    SLAVE_ADDRESSED_W               = 0x60,
+    SLAVE_AL_ADDRESSED_W            = 0x68,
+    SDA_STUCK                       = 0x70,
+    SCL_STUCK                       = 0x78,
+    SLAVE_DATA_RX_ACK               = 0x80,
+    SLAVE_DATA_RX_NAK               = 0x88,
+    SLAVE_STOP_OR_RESTART           = 0xA0,
+    SLAVE_ADDRESSED_R               = 0xA8,
+    SLAVE_AL_ADDRESSED_R            = 0xB0,
+    SLAVE_DATA_TX_ACK               = 0xB8,
+    SLAVE_DATA_TX_NAK               = 0xC0,
+    SLAVE_LAST_DATA_TX_ACK          = 0xC8,
+    SLAVE_GENERALCALL               = 0xD0,
+    SLAVE_GENERALCALL_AL            = 0xD8,
+    SLAVE_GENERALCALL_DATA_RX_ACK   = 0xE0,
+    SLAVE_GENERALCALL_DATA_RX_NAK   = 0xE8,
+    IDLE                            = 0xF8,
+    ILLEGAL_I2CCOUNT                = 0xFC
+}
+pca9665_status;
+
+typedef struct _speed_mode_st {
+    char    i2cmode;
+    char    i2cscll;
+    char    i2csclh;
+}
+speed_mode_st;
+
+speed_mode_st   speed_mode[ 3 ]     = {
+    { 0x00, 0x9D, 0x86 },
+    { 0x01, 0x2C, 0x14 },
+    { 0x02, 0x011, 0x09 }
+};
+
+int     buffer_mode_enable  = DISABLE;
+char    int_happened        = 0;
+char    op_mode_flag        = OP_MODE_MASTER_ONLY;
+
+void interrupt_handler_PCA9665( void ) {
+    int_happened    = 1;
+}
+
+void PCA9665_init( void ) {
+    write_data( I2CCON, 0x40 );
+    hw_wait_us( 1000 );
+
+    install_ISR( &interrupt_handler_PCA9665 );              //  interrupt service routine install
+
+    //  initialize PCA9955 registers
+}
+
+void set_speed_mode( int mode ) {
+    indirect_write( I2CMODE, speed_mode[ mode ].i2cmode );
+    indirect_write( I2CSCLL, speed_mode[ mode ].i2cscll );
+    indirect_write( I2CSCLH, speed_mode[ mode ].i2csclh );
+}
+
+void set_buffer_mode( int mode ) {
+    buffer_mode_enable  = mode;
+}
+
+int i2c_write( char addr, char *dp, char length, char restart_flag ) {
+    return (
+               buffer_mode_enable ?
+               i2c_write_buffer_mode( addr, dp, length, restart_flag )
+               :
+               i2c_write_byte_mode( addr, dp, length, restart_flag )
+           );
+}
+
+int i2c_read( char addr, char *dp, char length, char restart_flag ) {
+    return (
+               buffer_mode_enable ?
+               i2c_read_buffer_mode( addr, dp, length, restart_flag )
+               :
+               i2c_read_byte_mode( addr, dp, length, restart_flag )
+           );
+}
+
+
+int i2c_write_buffer_mode( char addr, char *dp, char length, char restart_flag ) {
+    int     done            = BUS_CONTINUE;
+    char    state;
+    char    return_value    = 0xFF;
+#ifdef  PCA9665_BURST_DATA_ACCESS
+#else
+    int     i;
+#endif
+
+    if ( 67 < length )
+        return ( 0xFE );
+
+    write_data( I2CCON, 0x61 );
+
+    while ( !done ) {
+        if ( int_happened ) {
+            int_happened    = 0;
+
+            state   = read_data( I2CSTA );
+
+            switch ( state ) {
+                case MASTER_START_TXed   :
+                case MASTER_RESTART_TXed :
+                    indirect_write( I2CCOUNT, length + 1 );
+                    write_data( I2CDAT, addr & 0xFE );
+
+#ifdef  PCA9665_BURST_DATA_ACCESS
+                    write_data_burst( I2CDAT, dp, length );
+#else
+                    for ( i = 0; i < length; i++ )
+                        write_data( I2CDAT, *dp++ );
+#endif
+
+                    write_data( I2CCON, 0x41 );
+                    break;
+                case MASTER_SLA_W_ACK  :  //  SLA+W TXed
+                case MASTER_DATA_W_ACK :  //  DATA TXed
+                    return_value    = 0x00;
+                    done            = BUS_STOP;
+                    break;
+                case MASTER_SLA_W_NAK  :
+                case MASTER_DATA_W_NAK  :
+                    return_value    = 0x01;
+                    done            = BUS_STOP;
+                    break;
+                case MASTER_ARB_LOST :
+                case SLAVE_AL_ADDRESSED_R :
+                case SLAVE_AL_ADDRESSED_W :
+                case SLAVE_GENERALCALL_AL :
+                    /*  bus should be released for other master  */
+                default :
+                    /*  unexpected bus error  */
+                    done    = BUS_RELEASE;
+                    break;
+            }
+        }
+    }
+
+    if ( OP_MODE_MASTER_ONLY == op_mode_flag )
+        done    = BUS_STOP;
+
+    if ( (BUS_STOP == done) && !restart_flag )
+        write_data( I2CCON, 0x50 );
+
+    return ( return_value );
+}
+
+int i2c_read_buffer_mode( char addr, char *dp, char length, char restart_flag ) {
+    int     done    = BUS_CONTINUE;
+    char    state;
+    char    return_value    = 0xFF;
+
+#ifdef  PCA9665_BURST_DATA_ACCESS
+#else
+    int     i;
+#endif
+
+    if ( 68 < length )
+        return ( 0xFE );
+
+    if ( !length )      //  zero byte read may cause invalid STOP to START signal output
+        return ( 0 );
+
+    write_data( I2CCON, 0x61 );
+
+    while ( !done ) {
+        if ( int_happened ) {
+            int_happened    = 0;
+
+            state   = read_data( I2CSTA );
+
+            switch ( state ) {
+                case MASTER_START_TXed   :
+                case MASTER_RESTART_TXed :
+                    write_data( I2CDAT, addr | 0x01 );
+                    indirect_write( I2CCOUNT, length | 0x80 );
+                    write_data( I2CCON, 0x41 );
+                    break;
+                case MASTER_SLA_R_ACK  :  //  SLA+R TXed
+                case MASTER_DATA_R_ACK :  //  DATA RXed
+                    return_value    = 0x00;
+                    done    = BUS_STOP;
+                    break;
+                case MASTER_SLA_R_NAK  :  //  SLA+R TXed
+                    return_value    = 0x01;
+                    done    = BUS_STOP;
+                    break;
+                case MASTER_DATA_R_NAK  :
+                    return_value    = length - (indirect_read( I2CCOUNT ) & 0x7F);
+                    done    = BUS_STOP;
+
+                    break;
+                case MASTER_ARB_LOST :
+                case SLAVE_AL_ADDRESSED_R :
+                case SLAVE_AL_ADDRESSED_W :
+                case SLAVE_GENERALCALL_AL :
+                    /*  bus should be released for other master  */
+                default :
+                    /*  unexpected bus error  */
+                    done    = BUS_RELEASE;
+                    break;
+            }
+        }
+    }
+
+#ifdef  PCA9665_BURST_DATA_ACCESS
+    read_data_burst( I2CDAT, dp, length );
+#else
+    for ( i = 0; i < length; i++ )
+        *dp++   = read_data( I2CDAT );
+#endif
+
+    if ( OP_MODE_MASTER_ONLY == op_mode_flag )
+        done    = BUS_STOP;
+
+    if ( (BUS_STOP == done) && !restart_flag )
+        write_data( I2CCON, 0x50 );
+
+    return ( return_value );
+}
+
+int i2c_write_byte_mode( char addr, char *dp, char length, char restart_flag ) {
+    int     done            = BUS_CONTINUE;
+    char    state;
+
+    write_data( I2CCON, 0x60 );
+
+    while ( !done ) {
+        if ( int_happened ) {
+            int_happened    = 0;
+
+            state   = read_data( I2CSTA );
+
+            switch ( state ) {
+                case MASTER_START_TXed   :
+                case MASTER_RESTART_TXed :
+                    write_data( I2CDAT, addr & 0xFE );
+                    write_data( I2CCON, 0x40 );
+                    break;
+                case MASTER_DATA_W_ACK :  //  DATA TXed
+                    length--;
+                    /*  FALLTHROUGH  */
+                case MASTER_SLA_W_ACK  :  //  SLA+W TXed
+                    if ( !length ) {
+                        done    = BUS_STOP;
+                        break;
+                    }
+                    write_data( I2CDAT, *dp++ );
+                    write_data( I2CCON, 0x40 );
+                    break;
+                case MASTER_SLA_W_NAK  :
+                case MASTER_DATA_W_NAK  :
+                    done    = BUS_STOP;
+                    break;
+                case MASTER_ARB_LOST :
+                case SLAVE_AL_ADDRESSED_R :
+                case SLAVE_AL_ADDRESSED_W :
+                case SLAVE_GENERALCALL_AL :
+                    /*  bus should be released for other master  */
+                default :
+                    /*  unexpected bus error  */
+                    done    = BUS_RELEASE;
+                    break;
+            }
+        }
+    }
+
+    if ( OP_MODE_MASTER_ONLY == op_mode_flag )
+        done    = BUS_STOP;
+
+    if ( (BUS_STOP == done) && !restart_flag )
+        write_data( I2CCON, 0x50 );
+
+    return ( length );
+}
+
+int i2c_read_byte_mode( char addr, char *dp, char length, char restart_flag ) {
+    int     done    = BUS_CONTINUE;
+    char    state;
+
+    if ( !length )      //  zero byte read may cause invalid STOP to START signal output
+        return ( 0 );
+
+    write_data( I2CCON, 0x60 );
+
+    while ( !done ) {
+        if ( int_happened ) {
+            int_happened    = 0;
+
+            state   = read_data( I2CSTA );
+
+            switch ( state ) {
+                case MASTER_START_TXed   :
+                case MASTER_RESTART_TXed :
+                    write_data( I2CDAT, addr | 0x01 );
+                    write_data( I2CCON, 0x40 );
+                    break;
+                case MASTER_DATA_R_NAK  :
+                    done    = BUS_STOP;
+                    /*  FALLTHROUGH  */
+                case MASTER_DATA_R_ACK :  //  DATA RXed
+                    *dp++   = read_data( I2CDAT );
+                    length--;
+                    /*  FALLTHROUGH  */
+                case MASTER_SLA_R_ACK  :  //  SLA+R TXed
+                    if ( !length )
+                        done    = BUS_STOP;
+
+                    if ( !done )
+                        write_data( I2CCON, (length == 1) ? 0x40 : 0xC0 );
+                    break;
+                case MASTER_SLA_R_NAK :
+                    done    = BUS_STOP;
+                    break;
+                case MASTER_ARB_LOST :
+                case SLAVE_AL_ADDRESSED_R :
+                case SLAVE_AL_ADDRESSED_W :
+                case SLAVE_GENERALCALL_AL :
+                    /*  bus should be released for other master  */
+                default :
+                    /*  unexpected bus error  */
+                    done    = BUS_RELEASE;
+                    break;
+            }
+        }
+    }
+
+    if ( OP_MODE_MASTER_ONLY == op_mode_flag )
+        done    = BUS_STOP;
+
+    if ( (BUS_STOP == done) && !restart_flag )
+        write_data( I2CCON, 0x50 );
+
+    return ( length );
+}
+
+void indirect_write( char idaddr, char data ) {
+    write_data( INDPTR, idaddr );
+    write_data( INDIRECT, data );
+}
+
+char indirect_read( char idaddr ) {
+    write_data( INDPTR, idaddr );
+    return ( read_data( INDIRECT ) );
+}