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

MCP23017
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
aaronik19



Joined: 25 Apr 2011
Posts: 297

View user's profile Send private message

MCP23017
PostPosted: Fri Apr 06, 2012 10:45 am     Reply with quote

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

View user's profile Send private message AIM Address

PostPosted: Fri Apr 06, 2012 2:02 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Apr 06, 2012 2:15 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Apr 06, 2012 3:34 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 07, 2012 7:03 am     Reply with quote

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

View user's profile Send private message AIM Address

PostPosted: Sat Apr 07, 2012 8:49 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 07, 2012 2:51 pm     Reply with quote

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 Smile
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Apr 07, 2012 4:38 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 07, 2012 6:28 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 07, 2012 6:48 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Apr 08, 2012 2:37 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Apr 08, 2012 6:54 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Apr 08, 2012 7:22 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Apr 08, 2012 7:31 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Apr 08, 2012 7:52 am     Reply with quote

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!!!!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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