View previous topic :: View next topic |
Author |
Message |
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
MCP23017 |
Posted: Fri Apr 06, 2012 10:45 am |
|
|
Dear All,
I am designing a project and for 8 input switches and 8 outputs I used the I2C device MCP23017. Now my doubt is for the input interrupt I need to connect the INTA (input port on MCP is Bank A) to the INT pin of the MCU? I am using 18F4452 |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Fri Apr 06, 2012 2:02 pm |
|
|
it appears that the the data sheets for both your external peripheral expander and the PIC makes your choices in INT? selection pretty clear.
have you actually BUILT some hardware to test
or are you thinking you will simulate first?
basically, is there a question in your post ?? |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Fri Apr 06, 2012 2:15 pm |
|
|
According to Microchip there is no such chip as the 18F4452... _________________ Google and Forum Search are some of your best tools!!!! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Apr 06, 2012 3:34 pm |
|
|
Quote: |
Now my doubt is for the input interrupt I need to connect the INTA (input
port on MCP is Bank A) to the INT pin of the MCU?
|
You don't have to connect it to the PIC's External interrupt pin. It's
optional to use it. The INTA or INTB pins can interrupt your PIC to tell
you if a change has occurred on the input pins of the MCP23017. Then
you can read the MCP23017 input port from the PIC. But if you don't
need to do that in your application, then you don't need the interrupt. |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Sat Apr 07, 2012 7:03 am |
|
|
Dear All,
First thanks for your reply. In fact I am using the PIC18f4550. Sorry for my typo error! I am waiting for the parts from RS (MCP23017) and at the moment I am doing some simulation to prepare the PIC Firmware. I know that I cannot rely 100% on the software simulation.
Thanks for your kind help and support. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Apr 07, 2012 8:49 am |
|
|
it all boils down to this:
if responding with minimum delay is critical in your use of the external I/O - then you NEED INT support.
On the other hand - if you have the leisure time to poll and no need to act in haste on state chanegs of the external port - then forget INTS . |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Sat Apr 07, 2012 2:51 pm |
|
|
Thanks, in this case INT is very important to me. The processor needs to act immediately after the user input a signal. So polling at this stage is very slow process!
Now for the INT, I need to enter/call I2C interrupt rountine in the EXT_INT? Thanks for your help but this is my first time that I am interfacing other chip with interrupt to PIC. Thanks for your explanation |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Apr 07, 2012 4:38 pm |
|
|
Create an int8 global flag variable. Clear it initially, in main(). Inside
the #int_ext routine, set the global flag to show that an interrupt has
occurred. This is how the interrupt routine can communicate with your
code in main(). It's done with the flag.
Then poll the global flag in a while() loop in main(). If it's set, then
clear it, and call a routine to read data from the MCP23017.
Also, at the start of main(), clear the INT_EXT interrupt by calling the
clear_interrupt() function. |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Sat Apr 07, 2012 6:28 pm |
|
|
thanks. I've read the datasheet several times and the only part I can't understand is were the GPIO and OLAT registers are mention. What is the difference exactly? What I understood, GPIO is holding the state of the outputs on OLAT. Correct? So if I want a particular pin as output, I need to address GPIO or directly to OLAT?
Thanks for your help as always |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sat Apr 07, 2012 6:48 pm |
|
|
Pages 22 and 23 in the datasheet have the info you need.
Remember to set the IODIRA or IODIRB to set pin direction.
Read the GPIO to get the state of the pins.
Quote: | The GPIO register reflects the value on the port.
Reading from this register reads the port. Writing to this
register modifies the Output Latch (OLAT) register. |
For output store the desired output bit state in the GPIOx register.
The GPIOx modifies the OLATx and the OLATx modifies the Output
pins. _________________ Google and Forum Search are some of your best tools!!!! |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Sun Apr 08, 2012 2:37 am |
|
|
I continued on the MCP23017 and after I setup the code, the controller seems that it is not "obeying" the PIC! My code is below:
The Main Program:
Code: | #include <18f252.h>
#use delay(crystal=20000000)
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
#include "mcp23017.C"
int8 count;
byte text;
#int_TIMER1
void TIMER1_isr(void)
{
}
#int_EXT
void EXT_isr(void)
{
}
void main()
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); //104 ms overflow
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
set_tris_A(0x00);
set_tris_B(0x00);
output_A(0x00);
output_B(0x00);
init_mcp();
count = 255;
//Example blinking LED program
while(true){
count--;
output_high(PIN_A0);
write_MCP(MCP23017_I2C_WRITE, _GPIOA, count);
delay_ms(1000);
output_low(PIN_A0);
delay_ms(1000);
text = read_MCP(MCP23017_I2C_WRITE, _IODIRB, MCP23017_I2C_READ);
}
}
|
the MCP23017 program:
Code: |
#define MCP23017_I2C_WRITE 0x40
#define MCP23017_I2C_READ 0x41
// MCP23017 REGISTERS
#define _IODIRA 0x00
#define _IPOLA 0x01
#define _GPINTENA 0x02
#define _DEFVALA 0x03
#define _INTCONA 0x04
#define _IOCON 0x05
#define _GPPUA 0x06
#define _INTFA 0x07
#define _INTCAPA 0x08
#define _GPIOA 0x09
#define _OLATA 0x0A
#define _IODIRB 0x10
#define _IPOLB 0x11
#define _GPINTENB 0x12
#define _DEFVALB 0x13
#define _INTCONB 0x14
#define _GPPUB 0x16
#define _INTFB 0x17
#define _INTCAPB 0x18
#define _GPIOB 0x19
#define _OLATB 0x1A
int ldata;
// ----------------------------------------------------------------------------
void write_MCP(unsigned char WriteAddress, unsigned char cmdByte, unsigned char data)
{
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(data); // First data byte pair as per command byte(cmd)
delay_us(20);
i2c_stop(); // stop condition
delay_us(50);
}
// ----------------------------------------------------------------------------
long int read_MCP(unsigned int WriteAddress, unsigned int cmdByte, unsigned int ReadAddress)
{
unsigned int data;
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(50);
i2c_start();
delay_us(20); // restart condition
i2c_write(ReadAddress); // Send slave address and clear (R_/W)
delay_us(20);
data = i2c_read(0); // Data from LSB or MSB of register
delay_us(20);
i2c_stop(); // stop condition
return(data);
}
// ----------------------------------------------------------------------------
void init_mcp()
{
output_float(PIN_C3);
output_float(PIN_C4);
// Wait for MCP23017 Expander Device to power-up.
delay_ms(250);
// Set-up selected I/O expander unit PORTA
write_MCP(MCP23017_I2C_WRITE, _IOCON, 0b10000010); // Direction of all data is output.
write_MCP(MCP23017_I2C_WRITE, _IODIRA, 0b00000000); // Direction of all data is output.
write_MCP(MCP23017_I2C_WRITE, _IPOLA, 0b00000000); // NonInvert all input polarities if active low
write_MCP(MCP23017_I2C_WRITE, _GPINTENA, 0b00000000); // INTERRUPT ON CHANGE OF PIN.
write_MCP(MCP23017_I2C_WRITE, _DEFVALA, 0b00000000); // Direction of all data is output.
write_MCP(MCP23017_I2C_WRITE, _INTCONA, 0b00000000); // Direction of all data is output.
write_MCP(MCP23017_I2C_WRITE, _GPPUA, 0b00000000); // Enable pullups
//write_MCP(MCP23017_I2C_WRITE, _INTFA, 0xF0); // READ-ONLY
//write_MCP(MCP23017_I2C_WRITE, _INTCAPA, 0x00); // READ-ONLY
//write_MCP(MCP23017_I2C_WRITE, _GPIOA, 0xFF); // READ-ONLY
//write_MCP(MCP23017_I2C_WRITE, _OLATA, 0x00); // Update o/p latch that controls the output.
// Set-up selected I/O expander unit PORTB
write_MCP(MCP23017_I2C_WRITE, _IODIRB, 0b11111111); // Direction of all data is output.
write_MCP(MCP23017_I2C_WRITE, _IPOLB, 0b00000000); // NonInvert all input polarities if active low
write_MCP(MCP23017_I2C_WRITE, _GPINTENB, 0b11111111); // INTERRUPT ON CHANGE OF PIN.
write_MCP(MCP23017_I2C_WRITE, _DEFVALB, 0b00000000); // Direction of all data is output.
write_MCP(MCP23017_I2C_WRITE, _INTCONB, 0b00000000); // Direction of all data is output.
write_MCP(MCP23017_I2C_WRITE, _GPPUB, 0b00000000); // Enable pullups
//write_MCP(MCP23017_I2C_WRITE, _INTFB, 0xFF); // Enable pullups
//write_MCP(MCP23017_I2C_WRITE, _INTCAPB, 0x00); // READ-ONLY
//write_MCP(MCP23017_I2C_WRITE, _GPIOB, 0x00); // READ-ONLY
//write_MCP(MCP23017_I2C_WRITE, _OLATB, 0x00); // Update o/p latch that controls the output.
}
|
the INT PINS remains both high every time. Now I configured the INTCON as "0" to compare always with the previous values and not with the DEFVAL register.
In the main program, I made a variable text to check the INTF register, to check which pin is causing the interrupt. In the program I am making a small task..every second the value on GPIOA is decreasing by one and ooutput the value on the port. Unfortunately, all LEDs remain OFF! |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sun Apr 08, 2012 6:54 am |
|
|
You are making things way too complicated. You are worried about
interrupts and you can't even talk to the chip!
Several things right off:
1. You said the processor was a 18F4550 now you have it as a 18F252
2. There is a missing a restart in your I2C commands. Go back and look at the datasheet page 7, notice the SR.
3. You are NAKing the read when you shouldn't. Do you see a NAK on Page 7 anywhere?
You need to comment out all the Interrupt and Timer lines for now and get the chip working first.. _________________ Google and Forum Search are some of your best tools!!!! |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Sun Apr 08, 2012 7:22 am |
|
|
I decided to change the PIC. It should not make any difference. The Ack in on page 8 after the control byte. At the moment everything is working except the INT! I need to read the GPIO to reset the interrupt flag.
I ignored the timers for the time being. I am going to use them in the next step. I left the code there as a reminder. |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Sun Apr 08, 2012 7:31 am |
|
|
For the INT the problem is that I connected the INTB directly to INT(RB0) on the MCU but the Interrupt is not being executed for some reason. I made also a transistor in case that the voltage level is not good but it was in vain. The proteus is saying Logic Contention Error.
Just to remind you that I know that simulation could fail but I am preparing the firmware till the components arrive. |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Sun Apr 08, 2012 7:52 am |
|
|
If you are using Proteus, that's a problem where I can't help you. It
is famous for not emulating accurately and could be large part of your
problem.
You made no comment about the missing restart. Did you fix it? If
Proteus is letting you get away with this, another problem with
Proteus.
I must be blind because I don't see anything on page 8 that says to
NAK. Figures 1-2 and 1-4 both show ACKs. _________________ Google and Forum Search are some of your best tools!!!! |
|
|
|