Mini board PCU9669 evaluation kit library
Dependents: mini_board_PCU9669
PCA9665_access.c
- Committer:
- nxp_ip
- Date:
- 2012-03-28
- Revision:
- 2:da1b02ca97ee
- Parent:
- 1:d7f7e0790f60
- Child:
- 3:930ef1a6bc99
File content as of revision 2:da1b02ca97ee:
/** 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 ) ); }