Atmel website | ARM Community | AVR freaks | Technical Support
Banner
Welcome to AT91SAM Community Forum
http://www.at91.com/samphpbb/

AT91F_TWI_WriteByte & AT91F_TWI_ReadByte infinite loop
http://www.at91.com/samphpbb/viewtopic.php?f=15&t=1988
Page 1 of 1

Author:  Satanic [ Tue Jul 11, 2006 6:47 pm ]
Post subject:  AT91F_TWI_WriteByte & AT91F_TWI_ReadByte infinite loop

Heya, i have been using the next 2 funtions for months, they are included in the basic examples. My application has been working fine while i have been in debugging, debug that i have done usually compiling to flash.

The problem came when i compiled to flash, where i have found that it gets in a loop forever, until the watchdog restarts the program (with watchdog disabled it hangs there forever).

You probably know the next code and maybe you are using it:

Code:

//*=========================================================
//*      WRITE
//*=========================================================
//*----------------------------------------------------------------------------
//* \fn    AT91F_TWI_WriteByte
//* \brief Send a byte to a slave device
//*----------------------------------------------------------------------------
int AT91F_TWI_WriteByte(const AT91PS_TWI pTwi ,int mode, int int_address, char *data2send, int nb)
{
   unsigned int status,counter=0,error=0;

   // Set TWI Internal Address Register
   if ((mode & AT91C_TWI_IADRSZ) != 0) pTwi->TWI_IADR = int_address;

   // Set the TWI Master Mode Register
     pTwi->TWI_MMR = mode & ~AT91C_TWI_MREAD;
   if(nb <2){
      pTwi->TWI_CR = AT91C_TWI_START | AT91C_TWI_MSEN | AT91C_TWI_STOP;
      pTwi->TWI_THR = *data2send;
   }
   else
   {
   // Set the TWI Master Mode Register
     for(counter=0;counter<nb;counter++){
          pTwi->TWI_CR = AT91C_TWI_START | AT91C_TWI_MSEN;
          if (counter == (nb - 1)) pTwi->TWI_CR = AT91C_TWI_STOP;
          status = pTwi->TWI_SR;
          if ((status & ERROR) == ERROR) error++;
          while (!(status & AT91C_TWI_TXRDY)){
               status = pTwi->TWI_SR;
               if ((status & ERROR) == ERROR) error++;
          }
          pTwi->TWI_THR = *(data2send+counter);
      }
   }
   status = pTwi->TWI_SR;
   if ((status & ERROR) == ERROR) error++;
   while (!(status & AT91C_TWI_TXCOMP)){
          status = pTwi->TWI_SR;
          if ((status & ERROR) == ERROR) error++;
    }
   return error;
}

//*=========================================================
//*      READ
//*=========================================================
//*----------------------------------------------------------------------------
//* \fn    AT91F_TWI_ReadByte
//* \brief Read a byte from a slave device
//*----------------------------------------------------------------------------
int AT91F_TWI_ReadByte(const AT91PS_TWI pTwi ,int mode, int int_address, char *data, int nb)
{
   unsigned int status,counter=0,error=0;


   // Set TWI Internal Address Register
   if ((mode & AT91C_TWI_IADRSZ) != 0) pTwi->TWI_IADR = int_address;

   // Set the TWI Master Mode Register
   pTwi->TWI_MMR = mode | AT91C_TWI_MREAD;

   // Start transfer
   if (nb == 1){
      pTwi->TWI_CR = AT91C_TWI_START | AT91C_TWI_STOP;
      status = pTwi->TWI_SR;
          if ((status & ERROR) == ERROR) error++;
      while (!(status & AT91C_TWI_TXCOMP)){
             status = pTwi->TWI_SR;
              if ((status & ERROR) == ERROR) error++;
          }
      *(data) = pTwi->TWI_RHR;
   }
   else{
      pTwi->TWI_CR = AT91C_TWI_START | AT91C_TWI_MSEN;
      status = pTwi->TWI_SR;
      if ((status & ERROR) == ERROR) error++;

   // Wait transfer is finished
           while (!(status & AT91C_TWI_TXCOMP)){
         status = pTwi->TWI_SR;
         if ((status & ERROR )== ERROR) error++;
          if(status & AT91C_TWI_RXRDY){
         *(data+counter++) = pTwi->TWI_RHR;
         if (counter == (nb - 1)) pTwi->TWI_CR = AT91C_TWI_STOP;
      }
      }
   }
   return 0;
}




I disable interrupts before i call any of those 2 functions and i enable them after. As i said both work fine while i run the code in ram but not when i run it in flash. It doesnt fail always, it happens just some random times, so i though that it was something with interrupts but it is not since i have them disabled.

For example in write funtion it hangs forever here:

Code:
          while (!(status & AT91C_TWI_TXRDY)){
               status = pTwi->TWI_SR;
               if ((status & ERROR) == ERROR) error++;
          }


In that case status has always status = 0x00000008 (that bit is always 1 it seems, even when it works fine).

I have tried everything and i have been not able to fix it, i'm thinking to implement it with soft, instead of using the Peripheral.

Some help would be welcome. Thanks in advance.

Author:  seulater [ Tue Jul 11, 2006 7:11 pm ]
Post subject: 

I too had this problem, that whole routine is kinda buggy (FYI).
I re-done the whole thing.

in the write routine try putting:

status = pTwi->TWI_SR;
if ((status & ERROR) == ERROR) error++;
while (!(status & AT91C_TWI_TXRDY)){
status = pTwi->TWI_SR;
if ((status & ERROR) == ERROR) error++;
}


after the "pTwi->TWI_THR = *(data2send+counter); "

TWI_SR is supposed to be checked after you update the TWI_THR and not
before.


Atmel, who includes it on their CD should scrutinize the software they use as samples. Tisk, Tisk, Atmel......

Author:  Satanic [ Wed Jul 12, 2006 1:21 pm ]
Post subject: 

Code:
// Set the TWI Master Mode Register
    for(counter=0;counter<nb;counter++)
      {
       pTwi->TWI_CR = AT91C_TWI_START | AT91C_TWI_MSEN;
       if(counter == (nb - 1))
          pTwi->TWI_CR = AT91C_TWI_STOP;
       pTwi->TWI_THR = *(data2send+counter);
       status = pTwi->TWI_SR;
       if((status & AT91C_TWI_NACK) == AT91C_TWI_NACK)
          error++;
       while (!(status & AT91C_TWI_TXRDY))
         {
          status = pTwi->TWI_SR;
          if ((status & AT91C_TWI_NACK) == AT91C_TWI_NACK)
             error++;
         }
      }// end loop for


It makes sense, but I still have the same problem :(


It never exits from:

Code:
       while (!(status & AT91C_TWI_TXRDY))
         {
          status = pTwi->TWI_SR;
          if ((status & AT91C_TWI_NACK) == AT91C_TWI_NACK)
             error++;
         }

Author:  seulater [ Wed Jul 12, 2006 5:39 pm ]
Post subject: 

replace

status = pTwi->TWI_SR;
if((status & AT91C_TWI_NACK) == AT91C_TWI_NACK)
error++;
while (!(status & AT91C_TWI_TXRDY))
{
status = pTwi->TWI_SR;
if ((status & AT91C_TWI_NACK) == AT91C_TWI_NACK)
error++;
}


with

do
{
status = TWI_SR;

if( (status & TWI_SR_TXCOMP) || (status & TWI_SR_NACK) )
{
// printf("Error\r\n");
return 1;
}

}while(!(status & TWI_SR_TXRDY));

return 0;




try that.

Page 1 of 1 All times are UTC + 1 hour [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/