Phytec 8564-RTC I²C interface library used in interrupt driven env.

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

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.