![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
sadlpx
Joined: 19 Feb 2004 Posts: 23
|
trouble with mcp23016 read and write |
Posted: Mon Feb 07, 2005 5:31 pm |
|
|
Attached is a peice of code i'm using to learn the MCP23016 io expander by microchip. So far i can write the data i want to GP0 (counting 0 > ff) no problem. now i only have two problemswhich i don't understand.
#1) when i do a read on GP1 the my led's tied to GP0 go off. I'm not writing to GP0 (or am i).
#2) I cannot read anything from GP1 except all 1's back. I hav eth epins tied to vcc (10K), I can pull the pins low with a jumper wire but no change in the data input.
I'm sure i missed something in the setup, and my code looks very much like the basic stamp artical and the Hitech C compiler listing
BUT it no work any ideas.
//////////////////////////////////////////////////////////////////
//
//
////////////////////////////////////////////////////////////////////////////////
#include <16F876.h>
#fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#device ICD=true
#use delay(clock=10000000) // value based on crystal
//Uses a Scott Edwards Electronics 4x20 Serial LCD module
#use rs232(baud=9600,parity=N,xmit=PIN_c4,rcv=PIN_B0,stream=RS232,invert,bits=8)
// Define project I2C communication pins
#define SCL_PIN PIN_A4
#define SDA_PIN PIN_A5
#use i2c(master, sda=SDA_pin, scl=SCL_pin)
// #include <MCP23016_1.c>
#include <BPP_420 LCD.C>
#define MCP23016_I2C_WRITE 0x40
#define MCP23016_I2C_READ 0x41
//=============================================
// #use standard_io(C)
// #use i2c(master,sda=PIN_C4,scl=PIN_C3)
// COMMAND BYTE TO REGISTER RELATIONSHIP : Table: 1-3 of Microchip MCP23016 - DS20090A
#define GP0 0x00
#define GP1 0x01
#define OLAT0 0x02
#define OLAT1 0x03
#define IPOL0 0x04 // INPUT POLARITY PORT REGISTER 0
#define IPOL1 0x05 // INPUT POLARITY PORT REGISTER 1
#define IODIR0 0x06 // I/O DIRECTION REGISTER 0
#define IODIR1 0x07 // I/O DIRECTION REGISTER 1
#define INTCAP0 0x08 // INTERRUPT CAPTURE REGISTER 0
#define INTCAP1 0x09 // INTERRUPT CAPTURE REGISTER 1
#define IOCON0 0x0A // I/O EXPANDER CONTROL REGISTER 0
#define IOCON1 0x0B // I/O EXPANDER CONTROL REGISTER 1
// BLOCK VARIABLE REGISTER
// ----------------------------------------------------------------------------
void write2Expander(unsigned char WriteAddress, unsigned char cmdByte, unsigned char lsbData) //, unsigned char msbData)
{
short int status;
i2c_start(); // start condition
delay_us(20);
i2c_write(WriteAddress); // Send slave address and clear (R/W_)
delay_us(20);
i2c_write(cmdByte); // Command byte and register to be written.
delay_us(20);
i2c_write(lsbData); // First data byte pair as per command byte(cmd)
delay_us(20);
i2c_stop(); // stop condition
delay_us(50); // delay to allow write (12us)min.
}
// ----------------------------------------------------------------------------
int readExpander(unsigned int WriteAddress, unsigned int cmdByte)
{
int Data, lsbData, msbData;
short int status,count;
startRead:
count=0; // Initialize read attempts counter.
i2c_start(); // start condition
delay_us(20);
i2c_write(WriteAddress); // Send slave address and clear (R/W_)
delay_us(20);
i2c_write(cmdByte); // Command byte and register to be written.
delay_us(20);
i2c_start();
delay_us(20); // restart condition
i2c_write(WriteAddress+1); // Send slave address and clear (R_/W)
delay_us(20);
/***/
lsbData = i2c_read(); // Data from LSB or MSB of register
delay_us(20);
i2c_stop(); // stop condition
delay_us(50); // delay to allow read (12us)min.
return(lsbData);
}
void main(void) {
int n, nn, o;
putc(3);
putc(12); // Clear LCD
putc(1);
// LCD_goto(0); // go to position 1
printf("I/O Tester");
write2Expander(MCP23016_I2C_WRITE, IODIR0, 0x00); // Direction of all data is output.
write2Expander(MCP23016_I2C_WRITE, IODIR1, 0xFF); // Direction of all data is input.
LCD_goto (20);
while(1) {
for (n=0; n<255; ++n) {
delay_ms(500);
nn = (n ^ 0xff);
write2Expander(MCP23016_I2C_WRITE, GP0, nn);
LCD_goto (20);
printf("\%03d ", n);
o = readExpander(MCP23016_I2C_WRITE, GP1);
LCD_goto (40);
printf("\%03d ",o);
} |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Feb 07, 2005 8:19 pm |
|
|
I have three comments:
1. You have altered the code from the examples shown in the AN245.
http://ww1.microchip.com/downloads/en/AppNotes/00245.zip
The sample code always writes or reads two bytes. You've changed
it to only handle one byte. Does that work ? All the text in the data
sheet always refers to two bytes:
Quote: | 1.9.2 WRITING THE REGISTERS
The I 2 C commands apply to one register pair to provide faster access.
1.9.3 READING THE REGISTERS
The data register defined by the command byte will be sent first,
followed by the other register in the register pair. |
2. The sample code for AN245 follows the CCS method of indicating
a NAK with a '0' parameter in the i2c_read() statement.
Quote: | // Receive first DATA byte (LSB) and acknowledge
MCP_LSB=i2c_read(1);
// Receive second DATA byte (MSB) and don't acknowledge
MCP_MSB=i2c_read(0); |
In your modified code, you have taken away the NAK on the final
i2c_read() statement. In your case, you only have one statement,
but it is therefore the "final" one, and must do the NAK. So even
if your proposed modification of only accessing one byte turns out
to work, it still is currently going to fail because you don't the '0'
parameter on the i2c_read().
3. You're correct to put the delay_us() statements in there.
The sample doesn't show them in the main source file,
but if you look in the i2cRxTx.c file, they are in there,
in the individual i2c functions.
My suggestion is to follow the sample code exactly. Access the two
bytes. Then if you get that working, try your changes later. |
|
![](templates/subSilver/images/spacer.gif) |
sadlpx
Joined: 19 Feb 2004 Posts: 23
|
MCP32016 problem solved |
Posted: Wed Feb 09, 2005 9:33 am |
|
|
I found the problem and posted working code in the code forum.
I rearranged the code as suggested by PCM programmer (thanks by the way) but was still having the inputs on GP0 turn off when i would read GP1. It was tough to find because it would work fine when i stepped through the code using debug (sometimes - depending on breakpoint).
Turns out the second I2Cstart within the read_MCP routine need more time. Increased delay from 20 to 50usec and the problem went away.
Hope this helps someone else. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|