A few posts before I wrote about about the project “Campus Door System “. In our real time environment part of the project we are using the miniMODUL-167 which is equipt with an RTC-8583.
For I²C < -> RTC interfacing we are using sources which can be downloaded from the Phytec ftp servers. For the whole project we have been using this source without problems 🙂
After rolling out the system to one of our customers a few weeks later the system suddenly stopped, only a reset could clear the situation. Our in-house systems have never shown this kind of symptoms. So what the hell was going on?
After some days I found out that the problem might be located on the RTC part. After the crash the RTC delivers such funny things like 56 h 78 m 99 s , lol, ok so the RTC counters only compare for equals thats for sure :-). But what part of our code is setting the RTC ?
To make it short, the problem was a combination of our system architecture and the way the used I²C library is working.
Because the I²C library has a low level layer which is responsible for generating the bit pattern of the I²C data, this part of the code is prone to wrong designed interrupt architecture.
Sample of the low level I²C:
/****************************************************************************/
/* sends one bit to I2C-bus, also used for sending ACKNOWLEDGE condition */
void I2CSendBit(BYTE State) {
// I2CDelay();
I2CPutSCL(0); /* setup SCL (redundant) */
// I2CDelay();
I2CPutSDA(State); /* setup SDA */
// I2CDelay();
I2CPutSCL(1); /* enable SDA writing */
// I2CDelay(); /* let SCL get stabilized High */
while(!I2CGetSCL()); /* wait until SCL-line is released */
// I2CDelay();
I2CPutSCL(0); /* disable SDA writing (SDA is now */
/* clocked) */
// I2CDelay();
I2CPutSDA(1); /* release SDA */
}
/****************************************************************************/
/* set SCL-line to desired state */
void I2CPutSCL(BYTE State)
{
if(!State)
{
I2C_PORT &= ~I2C_SCL_MSK; /* set SCL-Line to ZERO */
#ifdef __C166__
I2C_PORT_DIR |= I2C_SCL_MSK; /* set SCL-Pin for OUTPUT Mode */
#endif
/* enable output AFTER setting of */
/* correct level to avoid '1'-level */
/* spikes */
}
else
{
#ifdef __C166__
I2C_PORT_DIR &= ~I2C_SCL_MSK; /* set SCL-Pin for INPUT Mode */
#endif
/* this is possible because of the */
/* external pull-up resistor ! */
/* set SCL-line to ONE */
I2C_PORT |= I2C_SCL_MSK;
}
}
/****************************************************************************/
/* read state of SCL-line */
/* WARNING: This function should be used only if SCL-line is in High-level !*/
/* (This function is for used only for realizing the Slow-Down-Mode) */
BYTE I2CGetSCL(void)
{
#ifdef __C166__
I2C_PORT_DIR &= ~I2C_SCL_MSK; /* set SCL-Pin for INPUT Mode */
#endif
if(I2C_PORT&I2C_SCL_MSK)
return(1); /* read SCL-line status */
else
return(0);
}
This is exactly what happend. In-house we have only a certain amount of readers connected to the external buses of the access system. But our customer has over 100 readers installed. So the interrupt load was at a level where the situation could arise that at the moment where the I²C bit pattern is generated a few interrupts suspended the pattern generation. This leads in the worst case to a write instead of a read flag 🙂
A quick fix was to globally disable interrupts in I²C write situations or a better solution would be to move the accourding code to a high priojority interrupt.
I’m also writing this because some of my colleagues also use this lib – and yes they also do not read manuals 🙂
have fun
Mario