CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Problem with initialization on MCP23017 I/O expander

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
cbarberis



Joined: 01 Oct 2003
Posts: 172
Location: Punta Gorda, Florida USA

View user's profile Send private message Send e-mail

Problem with initialization on MCP23017 I/O expander
PostPosted: Thu Nov 01, 2012 4:29 pm     Reply with quote

I got a question for anyone that has used the MCP23017 A few years back I had a project where I used the SPI version (MCP23S17) and successfully wrote a firmware driver for it without much pain. So after briefly looking at the data sheet for the device it appeared to me that the only differences where the method of serial communications, all registers and op-codes seem the same. So I reversed engineered my old driver so a write_spi()or read_spi() just became a write_i2c() or read_i2c() and of course got rid of chip selects. For some reason I seem to be having a lot of issues trying to get this thing to write anything to the ports, actually it appears to me that it is not being itinitialized correctly. I have also tried modifying the code that comes with the Microchip MCP23X17 demo board without much success. I think I have read the data-sheet a few times now and there is no clue as to what the set-up instructions should be

Here is all I am trying to do with it:

Only use write operations on all 16 I/O pins I do not need to do reads just writes, so just to clarify things what should be the correct initialization code? If I understand correctly the sequence of sending serial info to this device is as follows:

send I2C start
send command byte via I2C ( command byte is: 0,1,0,0,A2,A1,A0,R/W)
wait for IC2 ACK
send restart IC2
send register address byte via I2C
wait for IC2 ACK
send restart IC2
send data byte via I2C
wait for IC2 ACK
send I2C Stop

Perhaps someone can shed some light on the subject or point me in the right direction. Below is the code that I am using for the device driver. I am writing this using the CCS PCD compiler for a PIC24HJ256GP206 the I2C port is working fine (I have already monitored the data using a logic analyzer) and I am already using another I2C EEPROM on the board which is working fine, so it is not a problem directly attribuited to my I2C bus.
Code:

#define I2CMODE 1
#define SPIMODE 0
#define WrtCmd  0
#define RdCmd   1


#defines are with IOCON.BANK = 0
**************************************************************/
#define IODIRA      0x00
#define IODIRB      0x01
#define IPOLA       0x02
#define IPOLB       0x03
#define GPINTENA    0x04
#define GPINTENB    0x05
#define DEFVALA     0x06
#define DEFVALB     0x07
#define INTCONA     0x08
#define INTCONB     0x09
#define IOCONA      0x0A
#define IOCONB      0x0B
#define GPPUA       0x0C
#define GPPUB       0x0D
#define INTFA       0x0E
#define INTFB       0x0F
#define INTCAPA     0x010
#define INTCAPB     0x011
#define GPIOA       0x012
#define GPIOB       0x013
#define OLATA       0x014
#define OLATB       0x015

#define HRDWADD 6 // device hard address
unsigned char gAddrPins = HRDWADD <<1;
unsigned char SerialMode = I2CMODE;
unsigned char gControlByte = 0x40;


void ResetMCP23X17(){
 output_low(IORESET);
 delay_us(100);
 output_float(IORESET);
}




void InitMCP( void )
{


//Configure 23017
  //Write23X17(GPPUA,  0x00);   // Pullups
  Write23X17(IOCONA, 0x40);    //
  Write23X17(IOCONB, 0x40);
  Write23X17(IODIRA, 0x00);   //All outs
  Write23X17(IODIRB, 0x00);   //All outs

}

/*************************************************************
   Function Name:  Write23X17                                         
   Return Value:   void                                           
   Parameters:     Register address, Data                   
   Description:    Writes a 23X17 register. I2C or SPI is in
                   global byte     
**************************************************************/
void Write23X17(unsigned char reg, unsigned char data)
{
   if(SerialMode == I2CMODE)   //If 23017 selected
      I2CWriteByte(reg, data); //
   else                                 //Else 23S17 is selected
     SPIWriteByte(reg, data); //
}


//****************************************
//   I2CWriteByte(unsigned char addr, unsigned char byte)
//   Writes a byte to the 23017
//****************************************
void I2CWriteByte(unsigned char reg, unsigned char data)
{ unsigned char ack;

   i2c_start();                   //Issue Start condition on I2C
//   delay_us(50);
   i2c_write( gControlByte | WrtCmd | gAddrPins);
   delay_us(150);     ///// <<<<<<<< I should be using a wait for IC2 ACK rather than a fixed delay...was not shure
                      /////////////// how to implement a wait for IC2 ACK, not sure this is the problem
 // i2c_stop();
   i2c_start();                   //same as re-start condition on I2C
  //delay_us(50);
   i2c_write( reg );
   delay_us(150);
 // i2c_stop();
 //   delay_us(20);
   i2c_start();                   // same as re-start condition on I2C
  //delay_us(50);
   i2c_write( data );
   delay_us(150);
   i2c_stop();
}
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Nov 02, 2012 6:46 am     Reply with quote

Code:
   delay_us(150);     ///// <<<<<<<< I should be using a wait for IC2 ACK rather than a fixed delay...was not shure
                      /////////////// how to implement a wait for IC2 ACK, not sure this is the problem
From the CCS manual on i2c_write:
Quote:
Returns: This function returns the ACK Bit.
0 means ACK, 1 means NO ACK, 2 means there was a collision if in
Multi_Master Mode.
The fact that i2c_write returns the ACK bit implies that i2c_write _does_ wait for the ACK bit. Nothing for you to do there, except perhaps checking the return value for an error.

Also get rid of all the I2C restarts, most likely these are your problem. I2c Restart is like an I2C Stop & Start in one command.

Try rewriting your write function as follows:
Code:
//****************************************
//   I2CWriteByte(unsigned char addr, unsigned char byte)
//   Writes a byte to the 23017
//****************************************
void I2CWriteByte(unsigned char reg, unsigned char data)
{
   i2c_start();
   i2c_write( gControlByte | WrtCmd | gAddrPins );
   i2c_write( reg );
   i2c_write( data );
   i2c_stop();
}
cbarberis



Joined: 01 Oct 2003
Posts: 172
Location: Punta Gorda, Florida USA

View user's profile Send private message Send e-mail

PostPosted: Fri Nov 02, 2012 10:22 am     Reply with quote

ckielstra,
You are 100% correct! The way I was sending the data via I2C was totally incorrect, using your cleaned-up method did the trick.
Thank you so much!

I will most likely post this driver on the forum library once I fully tested and debug it, so others don't have to suffer seeking answers.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group