|
|
View previous topic :: View next topic |
Author |
Message |
JerryR
Joined: 07 Feb 2008 Posts: 167
|
Intermittent bit shifts MCP23016 |
Posted: Thu Aug 21, 2008 12:14 pm |
|
|
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
|
|
Posted: Thu Aug 21, 2008 12:37 pm |
|
|
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
|
|
Posted: Thu Aug 21, 2008 12:45 pm |
|
|
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: 167
|
|
Posted: Thu Aug 21, 2008 1:13 pm |
|
|
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
Ttelmah: Yes, I meant a MCP23016, sorry for the tpyo
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
|
|
Posted: Thu Aug 21, 2008 2:56 pm |
|
|
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: 167
|
|
Posted: Thu Aug 21, 2008 4:16 pm |
|
|
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
|
|
Posted: Thu Aug 21, 2008 4:17 pm |
|
|
Also, as a test, try software i2c. Remove the FORCE_HW parameter. |
|
|
JerryR
Joined: 07 Feb 2008 Posts: 167
|
|
Posted: Thu Aug 21, 2008 5:00 pm |
|
|
Thanks PCM. I'll include this and test it. |
|
|
JerryR
Joined: 07 Feb 2008 Posts: 167
|
HEAT |
Posted: Fri Aug 22, 2008 7:22 am |
|
|
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
|
|
Posted: Fri Aug 22, 2008 7:51 am |
|
|
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: 167
|
|
Posted: Fri Aug 22, 2008 9:32 am |
|
|
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
|
|
Posted: Fri Aug 22, 2008 9:55 am |
|
|
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: 167
|
Problem solved |
Posted: Mon Aug 25, 2008 1:25 pm |
|
|
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.
|
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Mon Aug 25, 2008 2:23 pm |
|
|
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: 167
|
|
Posted: Mon Aug 25, 2008 2:53 pm |
|
|
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 |
|
|
|
|
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
|