Mini board PCU9669 evaluation kit library
Dependents: mini_board_PCU9669
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 }
Generated on Wed Jul 13 2022 01:53:41 by 1.7.2