Mini board PCU9669 evaluation kit library

Dependents:   mini_board_PCU9669

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PCA9665_access.c Source File

PCA9665_access.c

00001 /** A sample code for "mini board PCU9669/PCA9665"
00002  *
00003  *  @author  Akifumi (Tedd) OKANO, NXP Semiconductors
00004  *  @version 1.2
00005  *  @date    13-Jan-2015
00006  *
00007  *  Released under the MIT License: http://mbed.org/license/mit
00008  *
00009  *  An operation sample of PCU9669/PCA9665 I2C bus controller.
00010  *  The mbed accesses the bus controller's parallel port (8/2 bit address and 8 bit data) by bit-banging.
00011  *  The bit-banging is poerformed by PortInOut function of mbed library.
00012  *
00013  *    To make the code porting easier, all codes are partitioned into layers to abstract other parts.
00014  *    The mbed specific parts are concentrated in lowest layer: "hardware_abs.*".
00015  *    This module may need to be modified for the porting.
00016  *
00017  *    All other upper layers are writen in standard-C.
00018  *
00019  *    base code is written from 05-Sep-2011 to 09-Sep-2011.
00020  *    And demo code has been build on 11-Sep-2011.
00021  *    Debug and code adjustment has been done on 08-Sep-2011.
00022  *    Small sanitization for main.cpp. All mbed related codes are moved in to "hardware_abs.*". 13-Oct-2011
00023  *    hardware_abs are moved into parallel_bus library folder, 3 LED driver operation sample 13-Feb.-2012
00024  *    PCU9669 and PCA9665 codes are packed in a project 14-Feb-2012.
00025  *
00026  *    Before builidng the code, please edit the file mini_board_PCU9669/config.h
00027  *    Un-comment the target name what you want to target.
00028  */
00029 
00030 #include "PCA9665_access.h"
00031 #include "hardware_abs.h"
00032 
00033 #define     BUS_CONTINUE            0
00034 #define     BUS_STOP                1
00035 #define     BUS_RELEASE             2
00036 
00037 typedef enum {
00038     I2CSTA  = 0x0,
00039     INDPTR  = 0x0,
00040     I2CDAT,
00041     INDIRECT,
00042     I2CCON
00043 }
00044 pca9665_direct_registers;
00045 
00046 typedef enum {
00047     I2CCOUNT,
00048     I2CADR,
00049     I2CSCLL,
00050     I2CSCLH,
00051     I2CTO,
00052     I2CPRESET,
00053     I2CMODE
00054 }
00055 pca9665_indirect_registers;
00056 
00057 typedef enum {
00058     ILLEGAL_START_STOP              = 0x00,
00059     MASTER_START_TXed               = 0x08,
00060     MASTER_RESTART_TXed             = 0x10,
00061     MASTER_SLA_W_ACK                = 0x18,
00062     MASTER_SLA_W_NAK                = 0x20,
00063     MASTER_DATA_W_ACK               = 0x28,
00064     MASTER_DATA_W_NAK               = 0x30,
00065     MASTER_ARB_LOST                 = 0x38,
00066     MASTER_SLA_R_ACK                = 0x40,
00067     MASTER_SLA_R_NAK                = 0x48,
00068     MASTER_DATA_R_ACK               = 0x50,
00069     MASTER_DATA_R_NAK               = 0x58,
00070     SLAVE_ADDRESSED_W               = 0x60,
00071     SLAVE_AL_ADDRESSED_W            = 0x68,
00072     SDA_STUCK                       = 0x70,
00073     SCL_STUCK                       = 0x78,
00074     SLAVE_DATA_RX_ACK               = 0x80,
00075     SLAVE_DATA_RX_NAK               = 0x88,
00076     SLAVE_STOP_OR_RESTART           = 0xA0,
00077     SLAVE_ADDRESSED_R               = 0xA8,
00078     SLAVE_AL_ADDRESSED_R            = 0xB0,
00079     SLAVE_DATA_TX_ACK               = 0xB8,
00080     SLAVE_DATA_TX_NAK               = 0xC0,
00081     SLAVE_LAST_DATA_TX_ACK          = 0xC8,
00082     SLAVE_GENERALCALL               = 0xD0,
00083     SLAVE_GENERALCALL_AL            = 0xD8,
00084     SLAVE_GENERALCALL_DATA_RX_ACK   = 0xE0,
00085     SLAVE_GENERALCALL_DATA_RX_NAK   = 0xE8,
00086     IDLE                            = 0xF8,
00087     ILLEGAL_I2CCOUNT                = 0xFC
00088 }
00089 pca9665_status;
00090 
00091 typedef struct _speed_mode_st {
00092     char    i2cmode;
00093     char    i2cscll;
00094     char    i2csclh;
00095 }
00096 speed_mode_st;
00097 
00098 speed_mode_st   speed_mode[ 3 ]     = {
00099     { 0x00, 0x9D, 0x86 },
00100     { 0x01, 0x2C, 0x14 },
00101     { 0x02, 0x011, 0x09 }
00102 };
00103 
00104 int     buffer_mode_enable  = DISABLE;
00105 char    int_happened        = 0;
00106 char    op_mode_flag        = OP_MODE_MASTER_ONLY;
00107 
00108 void interrupt_handler_PCA9665( void )
00109 {
00110     int_happened    = 1;
00111 }
00112 
00113 void PCA9665_init( void )
00114 {
00115     write_data( I2CCON, 0x40 );
00116     hw_wait_us( 1000 );
00117 
00118     install_ISR( &interrupt_handler_PCA9665 );              //  interrupt service routine install
00119 
00120     //  initialize PCA9955 registers
00121 }
00122 
00123 void parallel_software_reset( void )
00124 {
00125     indirect_write( I2CPRESET, 0xA5 );
00126     indirect_write( I2CPRESET, 0x5A );
00127 }
00128 
00129 void set_speed_mode( int mode )
00130 {
00131     indirect_write( I2CMODE, speed_mode[ mode ].i2cmode );
00132     indirect_write( I2CSCLL, speed_mode[ mode ].i2cscll );
00133     indirect_write( I2CSCLH, speed_mode[ mode ].i2csclh );
00134 }
00135 
00136 void set_buffer_mode( int mode )
00137 {
00138     buffer_mode_enable  = mode;
00139 }
00140 
00141 int i2c_write( char addr, char *dp, char length, char restart_flag )
00142 {
00143     return (
00144                buffer_mode_enable ?
00145                i2c_write_buffer_mode( addr, dp, length, restart_flag )
00146                :
00147                i2c_write_byte_mode( addr, dp, length, restart_flag )
00148            );
00149 }
00150 
00151 int i2c_read( char addr, char *dp, char length, char restart_flag )
00152 {
00153     return (
00154                buffer_mode_enable ?
00155                i2c_read_buffer_mode( addr, dp, length, restart_flag )
00156                :
00157                i2c_read_byte_mode( addr, dp, length, restart_flag )
00158            );
00159 }
00160 
00161 
00162 int i2c_write_buffer_mode( char addr, char *dp, char length, char restart_flag )
00163 {
00164     int     done            = BUS_CONTINUE;
00165     char    state;
00166     char    return_value    = 0xFF;
00167 #ifdef  PCA9665_BURST_DATA_ACCESS
00168 #else
00169     int     i;
00170 #endif
00171 
00172     if ( 67 < length )
00173         return ( 0xFE );
00174 
00175     write_data( I2CCON, 0x61 );
00176 
00177     while ( !done ) {
00178         if ( int_happened ) {
00179             int_happened    = 0;
00180 
00181             state   = read_data( I2CSTA );
00182 //printf( "STA = 0x%02X\r\n", state );
00183 
00184             switch ( state ) {
00185                 case MASTER_START_TXed   :
00186                 case MASTER_RESTART_TXed :
00187                     indirect_write( I2CCOUNT, length + 1 );
00188                     write_data( I2CDAT, addr & 0xFE );
00189 #ifdef  PCA9665_BURST_DATA_ACCESS
00190                     write_data_burst( I2CDAT, dp, length );
00191 #else
00192                     for ( i = 0; i < length; i++ )
00193                         write_data( I2CDAT, *dp++ );
00194 #endif
00195                     write_data( I2CCON, 0x41 );
00196                     break;
00197                 case MASTER_SLA_W_ACK  :  //  SLA+W TXed
00198                 case MASTER_DATA_W_ACK :  //  DATA TXed
00199                     return_value    = 0x00;
00200                     done            = BUS_STOP;
00201                     break;
00202                 case MASTER_SLA_W_NAK  :
00203                 case MASTER_DATA_W_NAK  :
00204                     return_value    = 0x01;
00205                     done            = BUS_STOP;
00206                     break;
00207                 case ILLEGAL_START_STOP :
00208                 case ILLEGAL_I2CCOUNT :
00209                 case SCL_STUCK :
00210                     //  NOTE: In case of SCL_STUCK, the slave device may need to be reset
00211                     parallel_software_reset();
00212                     return ( 0xEE );
00213                 case MASTER_ARB_LOST :
00214                 case SLAVE_AL_ADDRESSED_R :
00215                 case SLAVE_AL_ADDRESSED_W :
00216                 case SLAVE_GENERALCALL_AL :
00217                     /*  bus should be released for other master  */
00218                 default :
00219                     /*  unexpected bus error  */
00220                     done    = BUS_RELEASE;
00221                     break;
00222             }
00223         }
00224     }
00225 
00226 #if 0
00227     if ( OP_MODE_MASTER_ONLY == op_mode_flag )
00228         done    = BUS_STOP;
00229 #endif
00230 
00231     if ( (BUS_STOP == done) && !restart_flag )
00232         write_data( I2CCON, 0x50 );
00233 
00234     return ( return_value );
00235 }
00236 
00237 
00238 int i2c_read_buffer_mode( char addr, char *dp, char length, char restart_flag )
00239 {
00240     int     done    = BUS_CONTINUE;
00241     char    state;
00242     char    return_value    = 0xFF;
00243 
00244 #ifdef  PCA9665_BURST_DATA_ACCESS
00245 #else
00246     int     i;
00247 #endif
00248 
00249     if ( 68 < length )
00250         return ( 0xFE );
00251 
00252     if ( !length )      //  zero byte read may cause invalid STOP to START signal output
00253         return ( 0 );
00254 
00255     write_data( I2CCON, 0x61 );
00256 
00257     while ( !done ) {
00258         if ( int_happened ) {
00259             int_happened    = 0;
00260 
00261             state   = read_data( I2CSTA );
00262 
00263             switch ( state ) {
00264                 case MASTER_START_TXed   :
00265                 case MASTER_RESTART_TXed :
00266                     write_data( I2CDAT, addr | 0x01 );
00267                     indirect_write( I2CCOUNT, length | 0x80 );
00268                     write_data( I2CCON, 0x41 );
00269                     break;
00270                 case MASTER_SLA_R_ACK  :  //  SLA+R TXed
00271                 case MASTER_DATA_R_ACK :  //  DATA RXed
00272                     return_value    = 0x00;
00273                     done    = BUS_STOP;
00274                     break;
00275                 case MASTER_SLA_R_NAK  :  //  SLA+R TXed
00276                     return_value    = 0x01;
00277                     done    = BUS_STOP;
00278                     break;
00279                 case MASTER_DATA_R_NAK  :
00280                     return_value    = length - (indirect_read( I2CCOUNT ) & 0x7F);
00281                     done    = BUS_STOP;
00282 
00283                     break;
00284                 case ILLEGAL_START_STOP :
00285                 case ILLEGAL_I2CCOUNT :
00286                 case SCL_STUCK :
00287                     //  NOTE: In case of SCL_STUCK, the slave device may need to be reset
00288                     parallel_software_reset();
00289                     return ( 0xEE );
00290                 case MASTER_ARB_LOST :
00291                 case SLAVE_AL_ADDRESSED_R :
00292                 case SLAVE_AL_ADDRESSED_W :
00293                 case SLAVE_GENERALCALL_AL :
00294                     /*  bus should be released for other master  */
00295                 default :
00296                     /*  unexpected bus error  */
00297                     done    = BUS_RELEASE;
00298                     break;
00299             }
00300         }
00301     }
00302 
00303 #ifdef  PCA9665_BURST_DATA_ACCESS
00304     read_data_burst( I2CDAT, dp, length );
00305 #else
00306     for ( i = 0; i < length; i++ )
00307         *dp++   = read_data( I2CDAT );
00308 #endif
00309 
00310 #if 0
00311     if ( OP_MODE_MASTER_ONLY == op_mode_flag )
00312         done    = BUS_STOP;
00313 #endif
00314 
00315     if ( (BUS_STOP == done) && !restart_flag )
00316         write_data( I2CCON, 0x50 );
00317 
00318     return ( return_value );
00319 }
00320 
00321 int i2c_write_byte_mode( char addr, char *dp, char length, char restart_flag )
00322 {
00323     int     done            = BUS_CONTINUE;
00324     char    state;
00325 
00326     write_data( I2CCON, 0x60 );
00327 
00328     while ( !done ) {
00329         if ( int_happened ) {
00330             int_happened    = 0;
00331 
00332             state   = read_data( I2CSTA );
00333 
00334             switch ( state ) {
00335                 case MASTER_START_TXed   :
00336                 case MASTER_RESTART_TXed :
00337                     write_data( I2CDAT, addr & 0xFE );
00338                     write_data( I2CCON, 0x40 );
00339                     break;
00340                 case MASTER_DATA_W_ACK :  //  DATA TXed
00341                     length--;
00342                     /*  FALLTHROUGH  */
00343                 case MASTER_SLA_W_ACK  :  //  SLA+W TXed
00344                     if ( !length ) {
00345                         done    = BUS_STOP;
00346                         break;
00347                     }
00348                     write_data( I2CDAT, *dp++ );
00349                     write_data( I2CCON, 0x40 );
00350                     break;
00351                 case MASTER_SLA_W_NAK  :
00352                 case MASTER_DATA_W_NAK  :
00353                     done    = BUS_STOP;
00354                     break;
00355                 case MASTER_ARB_LOST :
00356                 case SLAVE_AL_ADDRESSED_R :
00357                 case SLAVE_AL_ADDRESSED_W :
00358                 case SLAVE_GENERALCALL_AL :
00359                     /*  bus should be released for other master  */
00360                 default :
00361                     /*  unexpected bus error  */
00362                     done    = BUS_RELEASE;
00363                     break;
00364             }
00365         }
00366     }
00367 
00368     if ( OP_MODE_MASTER_ONLY == op_mode_flag )
00369         done    = BUS_STOP;
00370 
00371     if ( (BUS_STOP == done) && !restart_flag )
00372         write_data( I2CCON, 0x50 );
00373 
00374     return ( length );
00375 }
00376 
00377 int i2c_read_byte_mode( char addr, char *dp, char length, char restart_flag )
00378 {
00379     int     done    = BUS_CONTINUE;
00380     char    state;
00381 
00382     if ( !length )      //  zero byte read may cause invalid STOP to START signal output
00383         return ( 0 );
00384 
00385     write_data( I2CCON, 0x60 );
00386 
00387     while ( !done ) {
00388         if ( int_happened ) {
00389             int_happened    = 0;
00390 
00391             state   = read_data( I2CSTA );
00392 
00393             switch ( state ) {
00394                 case MASTER_START_TXed   :
00395                 case MASTER_RESTART_TXed :
00396                     write_data( I2CDAT, addr | 0x01 );
00397                     write_data( I2CCON, 0x40 );
00398                     break;
00399                 case MASTER_DATA_R_NAK  :
00400                     done    = BUS_STOP;
00401                     /*  FALLTHROUGH  */
00402                 case MASTER_DATA_R_ACK :  //  DATA RXed
00403                     *dp++   = read_data( I2CDAT );
00404                     length--;
00405                     /*  FALLTHROUGH  */
00406                 case MASTER_SLA_R_ACK  :  //  SLA+R TXed
00407                     if ( !length )
00408                         done    = BUS_STOP;
00409 
00410                     if ( !done )
00411                         write_data( I2CCON, (length == 1) ? 0x40 : 0xC0 );
00412                     break;
00413                 case MASTER_SLA_R_NAK :
00414                     done    = BUS_STOP;
00415                     break;
00416                 case MASTER_ARB_LOST :
00417                 case SLAVE_AL_ADDRESSED_R :
00418                 case SLAVE_AL_ADDRESSED_W :
00419                 case SLAVE_GENERALCALL_AL :
00420                     /*  bus should be released for other master  */
00421                 default :
00422                     /*  unexpected bus error  */
00423                     done    = BUS_RELEASE;
00424                     break;
00425             }
00426         }
00427     }
00428 
00429     if ( OP_MODE_MASTER_ONLY == op_mode_flag )
00430         done    = BUS_STOP;
00431 
00432     if ( (BUS_STOP == done) && !restart_flag )
00433         write_data( I2CCON, 0x50 );
00434 
00435     return ( length );
00436 }
00437 
00438 void indirect_write( char idaddr, char data )
00439 {
00440     write_data( INDPTR, idaddr );
00441     write_data( INDIRECT, data );
00442 }
00443 
00444 char indirect_read( char idaddr )
00445 {
00446     write_data( INDPTR, idaddr );
00447     return ( read_data( INDIRECT ) );
00448 }