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 support@ccsinfo.com

Intermittent bit shifts MCP23016

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



Joined: 07 Feb 2008
Posts: 164

View user's profile Send private message

Intermittent bit shifts MCP23016
PostPosted: Thu Aug 21, 2008 12:14 pm     Reply with quote

Hello:

I have been having a hard time tracking down an intermittent bit shift occurring in a project using a Microchip MCP23106 port expander. I would appreciate the group's critique of my code. The shift occurs from a lower position to the next upper position (example: bit 0 will shift to bit 1). Most always occurs in GP1.

The code is pretty simple. I am using a PIC18F4520 and compiling using v3.249 PCWH. The RTCC interrupt completes in approximately 150us. The calling routine, among other things, implements a PWM on four heaters. There is another interrupt active (RDA).

Has anyone seen a similar problem? Is there any way to "harden" the code?

Thanks for the group's help.

I2C routines:

Code:

//Send any command (including data) to MCP23016
//=====================================================================
void Send_Cmd_MCP(int8 AddressSelect, int8 Command, int8 P0, int8 P1)
{
   i2c_start();
      delay_us(20);
   i2c_write(MCP_write | (AddressSelect << 1));
      delay_us(20);
   i2c_write(Command);
      delay_us(20);
   i2c_write(P0);
      delay_us(20);
   i2c_write(P1);
      delay_us(20);
   i2c_stop();
      delay_us(50);                                         //(Rev E)  increased stop time
}
//====================================================================



Defines:
Code:


//==============================================================================
//For MCP23016 I2C Routines

#define MCP_write 0B01000000
#define MCP_read  0B01000001

#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

#define Device0   0x00     //I2C device at address 000b
#define Device1   0x01     //I2C device at address 001b
#define Device2   0x02     //I2C device at address 010b


Initialization, and calling routines:
Code:

//==============================================================================
//Writes all GPIO registers to MCP23106 devices
Set_Outputs()
{
Send_Cmd_MCP(Device0, OLAT0, ADR0_GP0,ADR0_GP1);         //sets outputs on compressors
}                                                        //and heaters

//==============================================================================

//==============================================================================

#int_rtcc                                                // This function is called every 5ms
void tics_isr()
{
set_timer0(157);                                         //set interrupt to occur each 5ms


StepperTimer++;                                          //increment stepper motor timer each 5ms
If (StepperTimer == 5)                                   //time to service stepper motors yet?
   {
   output_bit(TestOut2, 1);
   StepperTimer= 0;                                      //reset stepper motor timer
   ServeSteppers();                                      //service steppers every 25ms
   output_bit(TestOut2, 0);
   }


Max_Ticks_Period= Period / 0.005;                        //calculate max ticks per period

Heater_1_Off = Max_Ticks_period * Duty_Heat1;            //calculate off tick point for heater 1
Heater_2_Off = Max_Ticks_period * Duty_Heat2;            //calculate off tick point for heater 2
Heater_3_Off = Max_Ticks_period * Duty_Heat3;            //calculate off tick point for heater 3
Heater_4_Off = Max_Ticks_period * Duty_Heat4;            //calculate off tick point for heater 4

Current_Tick++;                                          //increment current tick

If (Current_Tick >= Max_Ticks_period)                    //if at maximum tick then...
   {
   Current_Tick = 0;                                     //start new cycle


//Heater 1 ON control at start of new cycle
   If ((Heater_1_Off == 0 )|| (EnableLoadHt1 == 0))      //heat duty is zero or heat not enabled
      {
      Bit_Clear(ADR0_GP0,0);                             //therefore:  heat off
      Set_Outputs();
      }

   else                                                  //heat on at zero
      {
      Bit_Set(ADR0_GP0,0);
      Set_Outputs();
      }
//Heater 2 ON control at start of new cycle
   If ((Heater_2_Off == 0 )|| (EnableLoadHt2 == 0))      //heat duty is zero or heat not enabled
      {
      Bit_Clear(ADR0_GP0,1);                             //therefore:  heat off
      Set_Outputs();
      }

   else                                                  //heat on at zero
      {
      Bit_Set(ADR0_GP0,1);
      Set_Outputs();
      }

//Heater 3 ON control at start of new cycle
   If ((Heater_3_Off == 0 )|| (EnableLoadHt3 == 0))      //heat duty is zero or heat not enabled
      {
      Bit_Clear(ADR0_GP0,2);                             //therefore:  heat off
      Set_Outputs();
      }

   else                                                  //heat on at zero
      {
      Bit_Set(ADR0_GP0,2);
      Set_Outputs();
      }

//Heater 4 ON control at start of new cycle
   If ((Heater_4_Off == 0 )|| (EnableLoadHt4 == 0))      //heat duty is zero or heat not enabled
      {
      Bit_Clear(ADR0_GP0,3);                             //therefore:  heat off
      Set_Outputs();
      }

   else                                                  //heat on at zero
      {
      Bit_Set(ADR0_GP0,3);
      Set_Outputs();
      }
   }

//Heater 1 OFF control seeking off point
If (Heater_1_Off ==  Current_Tick)
   {
   Bit_Clear(ADR0_GP0,0);                                //therefore:  heat off
   Set_Outputs();
   }

//Heater 2 OFF control seeking off point
If (Heater_2_Off ==  Current_Tick)
   {
   Bit_Clear(ADR0_GP0,1);                                //therefore:  heat off
   Set_Outputs();
   }

//Heater 3 OFF control seeking off point
If (Heater_3_Off ==  Current_Tick)
   {
   Bit_Clear(ADR0_GP0,2);                                //therefore:  heat off
   Set_Outputs();
   }

//Heater 4 OFF control seeking off point
If (Heater_4_Off ==  Current_Tick)
   {
   Bit_Clear(ADR0_GP0,3);                                //therefore:  heat off
   Set_Outputs();
   }

}
//==============================================================================

//Initialize all outputs
//==============================================================================
Init_All_Outputs()
{
int8  Count;

ADR0_GP0= 0X00;
ADR0_GP1= 0X00;                                          //set GP0 to all off, buzzer =1
ADR1_GP0= 0X00;
ADR1_GP1= 0X00;
ADR2_GP0= 0X00;
ADR2_GP1= 0X00;
                                                         //set GP1 to all off
Send_Cmd_MCP(Device0, OLAT0, ADR0_GP0,ADR0_GP1);
Send_Cmd_MCP(Device1, OLAT0, ADR1_GP0,ADR1_GP1);
Send_Cmd_MCP(Device2, OLAT0, ADR2_GP0,ADR2_GP1);

}
Ttelmah
Guest







PostPosted: Thu Aug 21, 2008 12:37 pm     Reply with quote

Presumably you mean 23016, not 23106.
First, get rid of the division by 0.005 in the interrupt routine. Multiply by 200 instead. Division takes significantly more time than multiplication. You will probably halve your interrupt time, by this single change...
Then get rid of the delays between your I2C instructions. These are not needed.
You don't show your I2C setups. Are you running in 100KHz mode or 400KHz mode?. What pull up resistors are you using on the I2C?. How long is your bus?. How are the heaters driven?. How is the PIC grounded?. How is the PIC's supply derived?. What smoothing has it got?. What speed is the RS232 driven?. Have you tried without the serial interrupt enabled?.

Best Wishes
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Aug 21, 2008 12:45 pm     Reply with quote

As an experiment, disable interrupts while doing the i2c operations.
This will tell you quickly if the interrupts are causing the problem.
Example:
Quote:

void Send_Cmd_MCP(int8 AddressSelect, int8 Command, int8 P0, int8 P1)
{
disable_interrupts(GLOBAL);
i2c_start();
delay_us(20);
i2c_write(MCP_write | (AddressSelect << 1));
delay_us(20);
i2c_write(Command);
delay_us(20);
i2c_write(P0);
delay_us(20);
i2c_write(P1);
delay_us(20);
i2c_stop();
delay_us(50); //(Rev E) increased stop time
enable_interrupts(GLOBAL);
}
JerryR



Joined: 07 Feb 2008
Posts: 164

View user's profile Send private message

PostPosted: Thu Aug 21, 2008 1:13 pm     Reply with quote

PCM: Yes! I'll give that a try. It extremely hard to see this happen. The controller is at a remote site with no one there that can test...just complain Rolling Eyes

Ttelmah: Yes, I meant a MCP23016, sorry for the tpyo Embarassed

To answer your questions:
Code:
#include <18F4520.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS,stream=PC)
#use i2c(master,sda=PIN_C4,scl=PIN_C3,FORCE_HW)

Using a 4.7K pull-up on both SDA and SCLK

Multiple MCP23016s used, longest run for I2C is approx 4" DS PCB

We are driving a low-current zero-crossing SSR which it turn drives a larger off-board contactor switching up to 200 amperes @ 440V.

Board uses an analog and digital ground which is connected together
through one 0ohm resistor. PIC uses 5v sourced from a LM340-T5
which dissipates approximately 600mW. Noise on Power supply less than 100mV p-p.

RS232 (which is actually RS485) is run at 9600 baud

I have not disabled the RDA to test yet. Might be the next step.

All good questions! See anything obvious?

Thanks so much!
Ttelmah
Guest







PostPosted: Thu Aug 21, 2008 2:56 pm     Reply with quote

How many 23016's?.
By 'default', the bus should be at 100K. Now the spec for the pull-ups, depends on the total capacitance present on the bus. With 4K7, at 100K, you have a maximum specified capacitance of about 240pF. You should be inside this, if the PCB is reasonably designed, but you might want to try lower pull-ups (minimum is about 1.8K for a 5v system).
Are you really confidant about your supply noise figure?. Unless the system used to measure this has a frequency response well into the GHz region, you may well have high frequency components that are larger. You don't mention what the smoothing is on the PIC supply. You want at least one capacitor that has really good high frequency performance (ceramic for example), really close to the PIC. Also similar close to each of the I/O expanders. Do the I2C lines run close to anything else?.

Best Wishes
JerryR



Joined: 07 Feb 2008
Posts: 164

View user's profile Send private message

PostPosted: Thu Aug 21, 2008 4:16 pm     Reply with quote

Ttelmah:

Again, thanks for your input. Yes, I am going to try running the I2C bus at STD (FAST=100000) and see what happens.

To answer your other questions:

MCP23016 - three on our design.

Yes, we do use 4.7K pull-ups and I could try lower to "help" the edge integrity (faster rise time).

I like good bypassing. We are using a combination of a ceramic 0.1uF and a low-ESR tant. on the PIC ( on the edge of the device at Vcc ). I also use 0.1uF ceramics on each port expander Vcc pin place close to Vcc. I haven't looked at the power supplies with a spectrum analyser, but that may be a good next step. Using a 250MHz scope, I see only 9mV p-p currently in a low electrical noise environment. We are working in a high electrical noise environment. The problem has only manifested itself in actual use in the high noise environment.

Again, thanks for your assistance.

We don't use the I2C except fr the port expanders
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Aug 21, 2008 4:17 pm     Reply with quote

Also, as a test, try software i2c. Remove the FORCE_HW parameter.
JerryR



Joined: 07 Feb 2008
Posts: 164

View user's profile Send private message

PostPosted: Thu Aug 21, 2008 5:00 pm     Reply with quote

Thanks PCM. I'll include this and test it.
JerryR



Joined: 07 Feb 2008
Posts: 164

View user's profile Send private message

HEAT
PostPosted: Fri Aug 22, 2008 7:22 am     Reply with quote

Apparently the MCP23016 is extremely temperature sensitive. Holding a heat gun near the device causes the bit swapping malidy. The external timing circuit is not as sensitive to heat, however.

We have done a fair job isolating the effects of the heat gun as being heat rather than EMC (created by the heat gun).

Does any of this sound familiar to anyone out there?

Thanks!
Ttelmah
Guest







PostPosted: Fri Aug 22, 2008 7:51 am     Reply with quote

Are you really _sure_ it is not the external clock circuit. Have you actually programmed IARES to 1, and tested on TP. I'd be most suspicious of this. How close to 1Mz is your clock?.
Have used these chips on a couple of units, that have been put through full environmental testing (soaked at temperatures between -30C, and +70C, for several days, including fast cycling), without problems. Presumably yours are 'I' temperature marked (have never seen any that are not).

Best Wishes
JerryR



Joined: 07 Feb 2008
Posts: 164

View user's profile Send private message

PostPosted: Fri Aug 22, 2008 9:32 am     Reply with quote

I know, it does sound strange. I've got a technician measuring TP and he's getting 1MHz +/- 10KHz at room temp and at heat gun temp (+40C). I sure would not have suspected a heat problem either. More later after more testing. Thanks for you continued interest!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Aug 22, 2008 9:55 am     Reply with quote

In the typical case, if you heat up a chip and it fails or becomes flakey,
there is a problem with:

1. The timing of the input signals to the chip may be wrong.
Look closely at the setup and hold times of the data to the clock.
Are they below the minimum requirements ? Look at the clock
frequency. Is it too high ?

2. There may be noise pulses on the board's Ground and/or Power
traces (tracks). When you heat up the chip, its input logic threshold
will get lower. This makes the chip more susceptible to noise.
If the Ground pin for the chip has noise pulses on it, you will often see
a problem as the chip heats up.


Any time that you have a flakey board and you can make it worse
by putting a heat gun on it, or make it better by freezing a chip with
chill spray, you should be looking at the things listed above.

If it's a small little chip that doesn't heat up by itself (normally) and its
not a defective batch, then I wouldn't jump on the idea that the chip
is the problem. (Unless you're heating it way out of spec). I would
look at the problem areas above.
JerryR



Joined: 07 Feb 2008
Posts: 164

View user's profile Send private message

Problem solved
PostPosted: Mon Aug 25, 2008 1:25 pm     Reply with quote

Problem solved. It turned out not to be a temp issue with the MCP23016, but a temp issue with a
T.I. 75176 RS485 driver / receiver close to the MCP23106. Communications to / from our controller from
a connected PC were being corrupted. Substituted equivalent LT or MAXIM devices for the TI, problem
went away at temperatures up to approximately 70C. TI devices began corrupting data at approximately 35C.
Entire lot of TI devices failed at lower temperatures.

Also hardened software with PCM and Ttelmah suggestions. THANKS GUYS! Also added a bit more robust
error detection on communications.

Again, thanks for the support group.
Very Happy
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Aug 25, 2008 2:23 pm     Reply with quote

I use that chip. The TI 75176. Can you tell be the Rev of silicon it was from?

I haven't seen the errors you describe,.. tho my protocol may resolve some
problems,.. But I may consider changing chips.

I'm going to write a simple test loop to see if I find anything similar.
I wonder if it has to do with its "thermal shutdown" at 150°C
tho it is characterized for operation from 0°C to 70°C.
JerryR



Joined: 07 Feb 2008
Posts: 164

View user's profile Send private message

PostPosted: Mon Aug 25, 2008 2:53 pm     Reply with quote

Treitmey: I didn’t mean to alarm everyone on TI’s 75176, this is probably an isolated batch. I’ll find a date code and send it to you. The temperature tolerance of the devices we tried was pathetic. The “flakiness” began around 30C-35C, no way the junction could be anywhere near 150C (or even 70C for that matter). We utilized two of these devices on a total of ten boards. All exhibit the same malady.

More later. Thanks
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