AW32: I2C Problem

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

AW32: I2C Problem

7,768 Views
BasePointer
Contributor II
Hi,
 
First of all, Freescale, I hate your datasheets !
But I like the forum, anyway... :smileyhappy:
 
I'm living interesting problem with I2C and EEPROM AT24C512BN.
If I debug test routine below, it works, "count" be equal to "okunan".
If I directly run the code, it fails at EE_ReadBuffer function. The function returns 0.
 
 
Code:
Test routine:  count = 0x89654321;  // unsigned long
  Init_i2c();  if(EE_WriteBuffer(0, &count, 4, I2C_ADR_EEPROM0))        DispMsg(MSG_FILL, 0);  else DispMsg(MSG_ERROR_CODE, 1);  if(EE_ReadBuffer(0, &okunan, 4, I2C_ADR_EEPROM0))        DispMsg(MSG_FILL, 0);  else DispMsg(MSG_ERROR_CODE, 2);    if(count == okunan)    DispMsg(MSG_FILL, 0);  else DispMsg(MSG_ERROR_CODE, 3);

 
If I change the i2c_start() function such as below: It start working in debug or not.
Code:
void i2c_start(void){  IIC1S_SRW = 0; // R/W bit = 0;  IIC1C_IICEN = 0;  IIC1C = 0b10011000;    IIC1C_MST = 1; // generate START condition}

 
I don't understand the problem due to the datasheet doesn't explain I2C module well.
Regards,
BP.
 
 
Code:
void Init_i2c(void){  // Bus = 18.432MHz;  // mul=4, ICR=0x0D => SCL Div=48, i2c_ Bus Freq = 96Khz, SDA Hold Time = 600ns  IIC1F = 0b10001101;  IIC1S_SRW = 0; // R/W bit = 0;  // Enable i2c module  // not generate ACK by master after transfer;  // TX mode  // Slave mode actually;  IIC1C = 0b10011000;  }void i2c_start(void){  IIC1C_MST = 1; // generate START condition}void i2c_stop(void){  IIC1C_MST = 0; // generate STOP condition;  }void i2c_restart(void){  IIC1C_RSTA = 1; // generate RESTART condition}void i2c_sendbyte(unsigned char data){  IIC1C_TX = 1; // transmit    IIC1D = data;  while(!IIC1S_IICIF); // wait until Transfer to complete;    IIC1S_IICIF = 1;}char i2c_getack(void){  return(!IIC1S_RXAK); // ACK gelmiş ise 1 döner, gelmemişse 0}unsigned char i2c_getbyte(char send_ack){  unsigned char data;    IIC1C_TX = 0; // set up to receive;    IIC1C_TXAK = send_ack—0:1;    data = IIC1D; // dummy read;  while(!IIC1S_IICIF); // wait until Transfer to complete;    IIC1S_IICIF = 1;    data = IIC1D; // read right data;    return(data);}/////////////////////////////////////////////////////////////////////////////////// EEPROM RUTINLERI Atmel AT24C512BN-SH-B veya ST M24512-RM/////////////////////////////////////////////////////////////////////////////////unsigned char EE_WaitForACK(unsigned char external_adr){  unsigned char counter = 100;    unsigned char ack;  unsigned char ControlByte = 0b10100000; // Yazma modu, A2, A1, A0 = 0    ControlByte |= ((external_adr << 1) & 0b00001110);    do  {    i2c_start();    i2c_sendbyte(ControlByte);    ack = i2c_getack(); // i2cgetack, ack alınmış ise 1 döner!    i2c_stop();      --counter; // her deneme 175uS sürüyor, 29 deneme > 5ms yapar.  } while(!ack && (counter != 0));    return(ack);}unsigned char EE_ReadBuffer(unsigned int Adr, unsigned char* Data, unsigned int size, unsigned char external_adr){  // Control Byte = 1 0 1 0 A2 A1 A0 R/W. unsigned char ControlByte = 0b10100000; // Yazma modu, A2, A1, A0 = 0 unsigned char AddrHigh = (Adr >> 8) & 0xFF; unsigned char AddrLow = (Adr & 0xFF);  ControlByte |= ((external_adr << 1) & 0b00001110);  i2c_start();  // Control Byte = 1 0 1 0 A2 A1 A0 R/W  i2c_sendbyte(ControlByte); if(!i2c_getack()) {  i2c_stop();  return(0); } // Address High Byte i2c_sendbyte(AddrHigh); if(!i2c_getack()) {  i2c_stop();  return(0); } // Address Low Byte i2c_sendbyte(AddrLow); if(!i2c_getack()) {  i2c_stop();  return(0); } // Read i2c_restart();  // Control Byte to read ControlByte |= 0b00000001; // Okuma modu i2c_sendbyte(ControlByte); if(!i2c_getack())  {  i2c_stop();  return(0); } do {  *Data++ = i2c_getbyte(size != 1);   } while(--size);  i2c_stop();  return(1);}char EE_WriteBuffer(unsigned int Adr, unsigned char* Data, unsigned int size, unsigned char external_adr){ unsigned int _PAGE = 0xFFFF; // önceki page  do  {     unsigned int CURRENT_PAGE = Adr & 0b1111111110000000; // page size 128 byte    if(CURRENT_PAGE != _PAGE)  {      // Control Byte = 1 0 1 0 A2 A1 A0 R/W.     unsigned char ControlByte = 0b10100000; // Yazma modu, A2, A1, A0 = 0     unsigned char AddrHigh = (Adr >> 8) & 0xFF;     unsigned char AddrLow = (Adr & 0xFF);          ControlByte |= ((external_adr << 1) & 0b00001110);      if(_PAGE != 0xFFFF)   {    i2c_stop();        if(!EE_WaitForACK(external_adr))       return(0);   }      i2c_start();    // Control Byte = 1 0 1 0 A2 A1 A0 R/W.   i2c_sendbyte(ControlByte);   if(!i2c_getack())   {    i2c_stop();        return(0);   }   // Address High Byte   i2c_sendbyte(AddrHigh);   if(!i2c_getack())   {    i2c_stop();        return(0);   }   // Address Low Byte   i2c_sendbyte(AddrLow);   if(!i2c_getack())   {    i2c_stop();        return(0);   }      _PAGE = CURRENT_PAGE;     } //if(CURRENT_PAGE != _PAGE)    i2c_sendbyte(*Data++);  if(!i2c_getack())  {   i2c_stop();   return(0);  }    Adr++; } while(--size); i2c_stop();  return(EE_WaitForACK(external_adr));}

 


Message Edited by BasePointer on 2007-09-12 04:50 PM
Labels (1)
0 Kudos
Reply
23 Replies

2,487 Views
FWFan
Contributor III

Hi All,

 

I'm using MC9S08QE128, I'm actually using poll and isr iic.  I got them to work but after I read from the eeprom, the SDA line won't pull up.  Do you guys have any idea?  I've included my code just in case.  The reading part is in the ISR routine.

 

The only way to pull it up again is to probe the SCL with the multimeter and then probe the SDA.  This seems to bring it up again.

 

Thank you,

FWFan.

0 Kudos
Reply

2,487 Views
MICROAR
Contributor I

3 years later...

 

I´m trying to make it work, I read all the messages.

My app: AW60, 24C256 eeprom, IIC polling, 4K7 pull ups, no drive strenght on ports.

So:

First is stopped at:

BRSET  IIC1S_IICIF,IIC1S,* ; Branch if flag is set (CF = 1)

 

Now it stops at:

 

 

; WAIT FOR IICIF FLAG OR TIMEOUT
; On exit CF = 0 if timeout occurred
 
WAIT_RXAK: 
     LDA    #20              ; Timeout 180 cycles
WLOOP12:
     BRSET  IIC1S_RXAK,IIC1S,WEXIT2 ; Branch if flag is set (CF = 1) ;<<<<<<<<<--- HERE!!!!
     DBNZA  WLOOP12           ; 9-cycle loop
WEXIT2:
     RTS

 

THIS IS THE COMPLETE ASM CODE:

It stops at WAIT:RXAK whit or whitout the "mad" JUSTRETURN.

 

 

Attached code.

 

Any help??

Thanks,

Gustavo.

 

0 Kudos
Reply

2,487 Views
Fonsi
Contributor I
Hello!
 
Yes, you are correct the data sheets are watered down a bit, sorry about that.
 
Looks like you are using polled code and eventhough I do not like it, when I benchmarked the I2C S08 and S12s, I found the following:
 
I can share with you is that I needed to be careful about my timing and delays were needed from the time I write to the data register and checking the flags for a byte completion flag set contition. It is also important to have the pullups between 2-4k Ohms or you will get hung up. The TC flag was not logically doing what I wanted to so I relied solely on IBIF flag.
 
Also the Baud Register must have the correct value and account for the correct transfer rate and setup/hold times. Please note that for one baud rate settings there may be 2 or 3 different values you can assign and only one will work for your setup/hold times correctly over temp.
 
Regards and I hope this helps you.
 
Edgar Saenz.
Product Engineering,
Austin Texas.
0 Kudos
Reply

2,487 Views
DaleUlan
Contributor I
I've been working on a similar problem - AW60, polled I2C. Here's what I found I needed to to to get it to work:
 
Immediately after setting IIC1C for the transfer, clear the interrupt flag (bset #1,IIC1S) - before writing the address byte to IIC1D
When writing to IIC1D, wait at least 12 clock cycles (jsr to a return) before brclr #1,IIC1S,*
When reading from IIC1D, wait at least 12 clock cycles between clearing the interrupt flag (bset #1,IIC1S) and reading the IIC1D register
After waiting for #0,IIC1S when transitioning from read to write mode, wait 12 cycles between each operation. Same thing when disabling ACK for the last transfer.
 
   Wait for #0,IIC1S
   Wait 12 Tcyc
   Set IIC1C for write mode
   Wait 12 Tcyc
   Read IIC1D
   Wait 12 Tcyc
   Wait for #1,IIC1S
   Clear #1,IIC1S
 
This seems to have worked for me. Hope it helps someone out there. I write in assembly code so perhaps C compilers put in the little delays just because. Anyways, it appears to work properly now.
0 Kudos
Reply

2,491 Views
Fonsi
Contributor I
Just to give you and Idea on what it takes to make this module to roll data out without a problem in Poll mode.
I am using some software semaphores so the code may not be easily portable but I am sharing this code so that you get to see some of what works. This is the same module as the one you are using the bit names have a small modification but it should be simple to make sense of the names. I left most of my comments in the code and I hope they help,.  10K pull up values are going to give you problems. I go for 5Ks if I were you.
 
I avoid do, while statements as they generate brclr/sets and those instructions tend to get stuck depending on the condition required. I always like the routine to return and error code and exit.
 
Regards,
 
Ed
 
 
 
 
 
//*****************************************************************//
//Inputs: char ID,char Read_Write,char NumberBytes
//Outputs:  IIC_Accepted
// Calling format : ack_flag=Send_IIC_Address(Control1,RW1,Total_Bytes) 
//*****************************************************************//
char Send_IIC_Address(char ID,char Read_Write,char NumberBytes)
{
char IIC_Accepted;
IIC_Accepted=0;
if(Slave_Flag==0)// if driver intends to be in Master mode
{
IBIF=1;
TX_RX_=1; // from master to slave
MS_SL_=1; // send START on clean slate
}
ID=ID<<1;
if(MS_SL_==1 && TX_RX_==1) 
{
IIC_Delay(1000000);//spacing between start and char.
// should not be needed to ensure byte reception
// continuity.
  if(Packet_Status==0)// 
  {
  IIC_DATA_ARRAY[0]=NumberBytes;
  IIC_Byte_Counter=0;
  Send(ID | Read_Write);
  }
  
  //IBDR=ID | Read_Write;// or the SRW bit with Address ID.
  //IIC_Delay(100);// worked polled at 900 at 968usec from end of last to begin of next.
    // worked polled at 500 at 59usec from ID to first byte.
  if(RXAK==0)
  {       
  IIC_Accepted=PORTB;
  IIC_Accepted=IIC_Accepted & 0xF7;
  PORTB=IIC_Accepted;// Turn on LED4 to indicate packet is transfer.
   if(Read_Write==1)
     Slave_Flag=0;// master mode
     IIC_Accepted=1;//Everything is cool let's get running   
//     Packet_Status=1;   // handled in the interrupt when polled here
  }
  else  
  MS_SL_=0;// sending stop
 
 
}
else

IBEN=0;
IBEN=1;// Bus is gone crazy
MS_SL_=1;// sending START
}    
 return IIC_Accepted;// if char =0 no response from slave node.
}
 
 
 
**************************************************************************************************************
 
//Description. Send packet will send a series of packets with
//incremental data n to n-1 where n-1=Number_Bytes-1 bytes.
char Send_Packet_Polled(char Number_Bytes)
{// send
char Byte_Counter=0;
char error_flag;
char Return_Val=0;
char Number_Fail=0;
char Number_Pass=0;
char chase_flag=1;
while(chase_flag==1)  
{
Return_Val=Send_IIC_Address(0x0E,0,4);//wp0xe
if (Return_Val==1)// good case.
{
Number_Pass++;
chase_flag=false;
}else
{
Number_Fail++; 
Byte_Counter=0;
return Byte_Counter;// Returns Number_Bytes-1 as completion flag 
     
}
}// end of while char_flag
 for (Byte_Counter=0;Byte_Counter<=Number_Bytes:smileywink:
 {
  // working with 7 but no second packet was moved to else.
   if(IBIF==1)      
    { 
     if(RXAK==0)
     {      
     //400 456 uSec works on packet only
     //500 568 uSec works
     //600 because START always given a macth hard to code  
      if(MS_SL_==1)
      {
       if(TX_RX_=1)
       {
       IIC_Delay(900000);/// could do a while (IBIF==1)      
       IBDR=Byte_Counter; // to generate brclr instruction.
       IIC_Delay(60);//100= 56usec working
           // 60=10usec spacing between bytes. Real   
       Byte_Counter++; // 55=8usec and not working real
       // 60 EM does not
       // 70 no
       // 100
       // 200
       }
     }
     else
      {
      Byte_Counter=Number_Bytes+1;
      return Byte_Counter;
      }
     
     }// end of else RXAK==0; 
     if(RXAK==1)
     { 
      error_flag=1;// abnormal condition
      Byte_Counter=Number_Bytes+1;
      MS_SL_=0;// send stop 
        IBIE=0;
        TX_RX_=1;      
      return Byte_Counter;// Returns Number_Bytes-1 as completion flag 
     }// end of if no ack from slave
     
    }// end of if(IBIF==1) case.
    else
    {// 
    Byte_Counter = Number_Bytes-1;
    }// end of if(IBIF==0) case.
   // end of good case
   
   if(Byte_Counter == Number_Bytes-1)
   {
   error_flag=0;//normal condition
   Byte_Counter=Number_Bytes+1;// end this loop
     MS_SL_=0;// send stop 
     IBIE=0;
     TX_RX_=1;      
   return Byte_Counter;// Returns Number_Bytes-1 as completion flag 
     }
  }// end of send Number_Bytes polled for loop.
     
}// end of send Packet Polled.
 
 
 

 
0 Kudos
Reply

2,491 Views
Fonsi
Contributor I
Hi,
 
I am not sure if you have resolved your I2C issue but it is somewhat difficult to debug code via emails. I can speculate and make suggestion.
 
I always advice I2C customers to run the module in Interrupt driven mode but if they must run in polled mode to make sure and place some delays between bytes and start and stop symbols. I have written I2C polled routines in the past and what I noticed is that Start and Stop symbols delays are needed. There is also  hardware considerations one must take into account to make sure that you avoid getting LOAs and the Master is forced into slave mode.  In and ideal world the code you present should work without a problem, but we never design in that environment.
 
If you are still having problems, please submit a technical service request and we will help you resolve your issue.
 
Issues we need to consider:
 
1. Is your bit rate correctly and compliant with your peripheral device?
 
2. Is your hardware set up correctly?
 
 
 
Regards,
 
Edgar Saenz.
TIC 16 bit Team Leader.
0 Kudos
Reply

2,491 Views
BasePointer
Contributor II
Hi Edgar,
 
I added some delay after start and stop. You can see my last implementation below. Unfortunately, it is  still not working for the second time.  That means EE_WriteBuffer function (1) in test routine  returns 1 but the EE_ReadBuffer function (2) never returns and crash at i2c_waitforflag. TCF never sets there.
 
My hardware (10Kohm pull-up on SCL and SDA) is working with my IIC software implementation.
Related EEPROMs support communication speed up to 400kHz, my hardware is so, too. (there is no caps on the bus) Oscilloscope output of the bus seems clean. I try communication at 100kHz.
 
Regards,
BP
 
Code:
  Test routine:  count = 0x89654321;  if(EE_WriteBuffer(0, &count, 4, I2C_ADR_EEPROM0))  ...........1      DispMsg(MSG_FILL, 0);  else DispMsg(MSG_ERROR_CODE, 1);  if(EE_ReadBuffer(0, &okunan, 4, I2C_ADR_EEPROM0))  ...........2        DispMsg(MSG_FILL, 0);  else DispMsg(MSG_ERROR_CODE, 2);    if(count == okunan)    DispMsg(MSG_FILL, 0);  else DispMsg(MSG_ERROR_CODE, 3);

 
 
 
Code:
void Wait_sh(unsigned char time){   unsigned int i, temp_t = time;   for (i=0;i<temp_t;i++)      {      asm nop;      }}void Init_I2C(void){  // Bus = 18.432MHz;  // mul=4, ICR=0x0D => SCL Div=48, i2c_ Bus Freq = 96Khz, SDA Hold Time = 600ns    IIC1C = 0;/*  PTCD_PTCD0 = 0;  PTCD_PTCD0 = 0;    PTCDD_PTCDD0 = 0;  PTCDD_PTCDD0 = 0;  PTADS = 0;  PTASE = 0;*/  Wait_sh(80);    IIC1A = 0;  IIC1F = 0b10001101;  IIC1C = 0b10000000;    Wait_sh(80);}void i2c_start(void){     Init_I2C();    IIC1S = 0b10010010; // clear interrupts     IIC1C = 0b10111000; // Start, TX, NOACK    Wait_sh(80);}void i2c_stop(void){  IIC1S = 0b10010010; // clear interrupts  IIC1C = 0b10000000;  Wait_sh(80);}void i2c_restart(void){  IIC1C = 0b10111100; // Start, TX, NOACK, RESTART  Wait_sh(80);}char i2c_waitforflag(void){  IIC1SSTR status;    Wait_sh(80);    do  {    status.Byte = IIC1S;  } while(!status.Bits.TCF);    IIC1S = 0b10010010; // clear interrupts    return(!status.Bits.RXAK);}char i2c_sendbyte(unsigned char data){  if(IIC1C != 0b10111000) IIC1C = 0b10111000;  IIC1D = data;    return(i2c_waitforflag());}unsigned char i2c_getbyte(char send_ack){  unsigned char data;    if(send_ack) IIC1C = 0b10100000; // RX, SEND_ACK   else IIC1C = 0b10101000; // RX, NO_ACK  IIC1D;  i2c_waitforflag();  data = IIC1D; // read right data;    Wait_sh(80);    return(data);}

 
 
Code:
unsigned char EE_WaitForACK(unsigned char control_byte){  unsigned char counter = 200;    unsigned char ack;    unsigned char ControlByte = control_byte;    ControlByte &= 0b11111110;    do  {    i2c_start();    ack = i2c_sendbyte(ControlByte);        i2c_stop();      --counter; // her deneme 175uS sürüyor, 29 deneme > 5ms yapar.  } while(!ack && (counter != 0));    return(ack);}char EE_ReadBuffer(unsigned int Adr, unsigned char* Data, unsigned int size, unsigned char external_adr){  // Control Byte = 1 0 1 0 A2 A1 A0 R/W. unsigned char ControlByte = 0b10100000; // Yazma modu, A2, A1, A0 = 0 unsigned char AddrHigh = (Adr >> 8) & 0xFF; unsigned char AddrLow = (Adr & 0xFF);  ControlByte |= ((external_adr << 1) & 0b00001110);  i2c_start();  // Control Byte = 1 0 1 0 A2 A1 A0 R/W  if(!i2c_sendbyte(ControlByte)) {  i2c_stop();  return(0); } // Address High Byte  if(!i2c_sendbyte(AddrHigh)) {  i2c_stop();  return(0); } // Address Low Byte  if(!i2c_sendbyte(AddrLow)) {  i2c_stop();  return(0); } // Read i2c_restart();   // Control Byte to read ControlByte |= 0b00000001; // Okuma modu   if(!i2c_sendbyte(ControlByte))  {  i2c_stop();  return(0); } do {  *Data++ = i2c_getbyte(size != 1);   } while(--size);  i2c_stop();  return(1);}char EE_WriteBuffer(unsigned int Adr, unsigned char* Data, unsigned int size, unsigned char external_adr){ unsigned int _PAGE = 0xFFFF; // önceki page   // Control Byte = 1 0 1 0 A2 A1 A0 R/W.  unsigned char ControlByte = 0b10100000; // Yazma modu, A2, A1, A0 = 0   do  {     unsigned int CURRENT_PAGE = Adr & 0b1111111110000000; // page size 128 byte    if(CURRENT_PAGE != _PAGE)  {     unsigned char AddrHigh = (Adr >> 8) & 0xFF;     unsigned char AddrLow = (Adr & 0xFF);          ControlByte |= ((external_adr << 1) & 0b00001110);      if(_PAGE != 0xFFFF)   {    i2c_stop();        if(!EE_WaitForACK(external_adr))       return(0);   }      //i2c_start();   i2c_start();    // Control Byte = 1 0 1 0 A2 A1 A0 R/W.      if(!i2c_sendbyte(ControlByte))   {    i2c_stop();        return(0);   }   // Address High Byte      if(!i2c_sendbyte(AddrHigh))   {    i2c_stop();        return(0);   }   // Address Low Byte      if(!i2c_sendbyte(AddrLow))   {    i2c_stop();        return(0);   }      _PAGE = CURRENT_PAGE;     } //if(CURRENT_PAGE != _PAGE)    if(!i2c_sendbyte(*Data++))  {   i2c_stop();   return(0);  }    Adr++; } while(--size); i2c_stop();  return(EE_WaitForACK(ControlByte));}

 
0 Kudos
Reply

2,491 Views
Fonsi
Contributor I
Hello,
 
In the issue of pull-ups while set at 10k, I have to say this value is too high it may work at 400KHz but I have experienced that as you star running in real environment, you will loose packets. 4.7kOhms is what I have used in the past and achieved 100% success transfer from the Master to the slave and vice versa. If you notice for a 400KHz speed there are only 2 settings to select the proper Setup and Hold settings for your device.
 
  Someone shared with you that they resorted to a bit banged routine to get things to work correctly and that is fine but that was not necessary specially when the final application will use and interrrupt driven firmware and many events have to be handled in the background.  When dealing with polled code you have to make sure you have the correct delay and that you monitor the correct condition flags before writing to the I2C data register.
 
I also agree that the I2C documentation is only sharing where the control and status registers are place and what their functions are. I also agree that we should have a document explaining how the Phillips specified requirements are implement by the module. There are however, 4 I2C appnotes currently published that are supposed illustrate how one can use the module for communications.
 
Writen code just illustrates your intentions with the module but do very little to really figure out what is really going on in your MCU. Transfering an entire project to allow us to run it in real system, would allow any of our support engineers to debug efficiently and this is the reason why I have suggested that we discuss in more details and find out what the root cause is. .
 
In summary:
 
-5k or lower on SDA and SCL, If you need a pullup lower than 4.7K, your system is not properly filtered.
 
-I2C interrupt driven Driver should be written to allow the I2C state machine schedule I2C protocol events.
 
Regards,
 
 
Regards,
 
Edgar Saenz.
 
 
0 Kudos
Reply

2,491 Views
Smoke_N_Mirrors
Contributor I
Folks,
Just want to make sure y'all are aware of the Errata on the "AW" series:
"IIC Does Not Function When High Drive Strength Is Enabled on the IIC Pins"

http://www.freescale.com/files/microcontrollers/doc/errata/MSE9S08AW60_5M75B.pdf?fsrch=1&WT_TYPE=Err...

We found this several years ago and Freescale added it to the errata.  I don't think it ever got fixed in any die revision.  It's only a problem if you are using the I2C peripheral, not if you are "bit-banging" the I2C.

"Description
IIC operation requires open drain configuration but when the PTxDS bit associated with the IIC SDA or
SCL pin is set for high drive strength (PTxDS = 1) the pin will be in complementary drive mode instead of
open drain mode. This will cause IIC communication conflicts that lead to IIC malfunction.
(Because some devices can't back-drive the CPU driving SDA high.  Note that Processor Expert's "Bean" generated code sets SDA/SCL to HIGH DRIVE, in cpu.c, which does not work!)

Workaround
The PTxDS bits associated with the IIC SDA and SCL pins should be cleared for low drive strength
operation. This configuration will ensure that the corresponding pin will enter open drain mode and IIC
communications will function correctly. The IIC pull-up resistor in the final application may need to be
modified to account for the lower drive strength of the SDA and SCL pins."

So....
If you are using high drive strength on the SDA / SCL lines, I2c works intermittently, depending on the drive strength of other devices on the line, and the pullup values.  We also found that if you I2C line does get hung (say by temporarily shorting SDA to ground, or noise, or ESD hit), that you have RE-WRITE the SDA/SCL drive strength bit back to low drive to "unhang" the I2C bus.
We lost a lot of hair on this one! 

-Dave M

0 Kudos
Reply

2,491 Views
bigmac
Specialist III
Hello BP,
 
I agree that 10k pull-up resistors are somewhat on the high side, particularly for a 400kHz clock.  However, your posted code indicates that you have a 96kHz clock, and since your capacitive bus loading is likely to be substantially less than the 400pF upper limit for this clock rate, I doubt that this is your current problem.
 
I did some comparison of your posted code with that shown in AN3291 (for the 9S08GB60 device), and found a difference that might be significant -
 
While your code seems excessively circuituous, it would appear to resolve to the following sequence for the transmission of each byte by the master -
  1. Write byte value to IIC1D.
  2. Wait for TCF flag to become set.
  3. Attempt to clear TCF, ARBL and IICIF read only flags.
  4. Wait for RXAK flag to become set.
By comparison, the similar code shown within AN3291 (which does not use use IIC interrupt) does the following -
  1. Write byte value to IIC1D.
  2. Wait for IICIF flag to become set.
  3. Clear the IICIF flag only.
  4. Wait for RXAK flag to become set.

   IIC1D = data;
   while (!IIC1S_IICIF);     // wait until interrupt flag
   IIC1S_IICIF = 1;          // clear flag
   while (IIC1S_RXAK);       // Wait for ACK from slave

So the important aspect appears not that it be necessary to implement interrupts, but that the interrupt flag IICIF should be the flag that is tested and cleared, rather than TCF.  If this is correct, the issue appears most likely that the IICIF flag becomes set some time after the TCF flag is set, and the attempt to clear the flags does not clear the IICIF flag (which is obviously a mandatory requirement, although not stated in the data sheet).

The importance of testing the IICIF flag (and not TCF) is suggested by the author of AN3291, in the following thread, that also addresses a bug present in the original release of the application note -http://forums.freescale.com/freescale/board/message?board.id=8BITCOMM&message.id=3785

The application note makes no mention of the need for an extra delay following START or STOP conditions.  It might have been more instructive if the reason for the previous suggestion of their inclusion was given, in order to appreciate what the magnitude of the delay might be.

Finally, I notice that your code for the generation of START and STOP seems more complex than the application note would suggest -

   IIC1C_TXAK = 0;           // RX/TX = 1; MS/SL = 1; TXAK = 0
   IIC1C |= 0x30;            // generate START

and

   IIC1S_IICIF = 1;          // clear interrupt flag
   IIC1C_MST = 0;            // generate STOP

Regards,
Mac



Message Edited by bigmac on 2007-09-29 03:49 PM
0 Kudos
Reply

2,491 Views
Fonsi
Contributor I
IICIF flag is the only flag I dealt with in my driver which has polled and interrupts driven utilities. TCF is there as a status flag and is seems to be there to indicate when the Transmission is complete, how that status flag is used in code is still unknow to me but I am sure there is a use for it. The same module is used on the S12s where I did most of my IIC testing, and yes you are correct, the code in polled style works and can be made to run but I found that for any application where the MCUs task is more complicated, Interrupts is the way to go and since everything I get drafted into is not simple, I love Interrupts. You of course do not have to. Sounds to me you have figured it out and thank you for using our devices.  It is not that complex to watch the behavior of the device, specially when the using the Debugger under CW, one only needs to set the Memory window in periodic display mode and run the Master to brake and trace on every IICDR statement, or in machine code at STA 0xIICDR. One can see with of the flags are set and clear on each byte transaction. I was hoping you could open an SR so that I can share my un published appnote with you but since you are well on your way. More power to you.
 
Edgar.
0 Kudos
Reply

2,491 Views
BasePointer
Contributor II
Hi to all,
 
Thank you for your interest.
Here is my last implementation.
Now I'm living problem only with i2c_getbyte() function.
It is returning either 0 or holding on at line: while(!IIC1S_IICIF);
I'm using this function to read sequential bytes.
Do you know how we exactly start reading sequence?
Or what are the conditions that cause reading sequence not to start?
The communication speed is 96Khz with 10Kohm pull-ups and no capacitance. (also tried with 22pF caps without chance)
My scope is in the service now, I will send some images about SCL and SDA in a few days.
 
 
Code:
void i2c_clearflags(void){  IIC1S_IICIF = 1;  IIC1S_TCF = 0;  IIC1S_ARBL = 0;}void i2c_start(void){  i2c_clearflags();    IIC1S_SRW = 0; // master will send data    IIC1C = 0b10111000; // Start, TX, NOACK      Wait_sh(80);}void i2c_stop(void){  i2c_clearflags();  IIC1S_SRW = 0; // master will send data    IIC1C = 0b10000000;    Wait_sh(80);}void i2c_restart(void){  i2c_clearflags();    IIC1S_SRW = 0; // master will send data  IIC1C = 0b10111100; // Start, TX, NOACK, RESTART    Wait_sh(80);}char i2c_waitforflag(void){  IIC1SSTR status;    do  {    status.Byte = IIC1S;  } while(!status.Bits.IICIF);    i2c_clearflags();      return(!status.Bits.RXAK);}char i2c_sendbyte(unsigned char data){  if(IIC1C != 0b10111000) IIC1C = 0b10111000;  IIC1D = data;    return(i2c_waitforflag());}unsigned char i2c_getbyte(char send_ack){  unsigned char data;    if(IIC1C_TX)  {    IIC1C_TX = 0;    IIC1C_TXAK = 0;            data = IIC1D; // initiate first reading sequence  }    while(!IIC1S_IICIF);  i2c_clearflags(); if(send_ack) IIC1C_TXAK = 0;  else IIC1C_TXAK = 1;        data = IIC1D; // read right data    return(data);}

 
Regards,
BP.
0 Kudos
Reply

2,491 Views
bigmac
Specialist III
Hello BP,
 
Firstly, there seems to be confusion about some of the flags -
SRW is a read only flag, and is of no interest for master operation.  Similarly, the ARBL flag is of no interest with a dedicated master.  Anyway, it is cleared by writing 1, not 0.  The TCF flag is automatically cleared on the next read or write to IIC1D register.  This leaves only the IICIF flag to be concerned about in the flag clearing process.
 
I don't know why you chose not to use standard bit definitions within the i2c_waitforflag() function.  Also, the intention of the line
return(!status.Bits.RXAK);
seems obscure.  It certainly doesn't wait until the RXAK  flag is set.
 
You should check the actual requirements in the data sheet for the EEPROM device, but to start the reading sequence, after sending the  address bytes, you will probably need to generate a repeated start, and then send the control byte again with the RW bit  set for read.  Then clear the IIC1C_TX bit for read, set the IIC1C_TXAK bit to disable acknowledge, and do a dummy read of the IIC1D register.
 
I suggest you examine the left hand part of Fig. 13.1 in the data sheet for the AW60.  Even though the flow diagram pertains to an ISR, a similar sequence of events will be required when the flag is polled.
 
Finally, do not add any capacitors to the bus - the least capacitance the better.
 
Regards,
Mac
 
0 Kudos
Reply

2,491 Views
Witztronics
Contributor IV
Take a look at AN3291.
 
It explains everything you need to know to use the I2C on the HC(S)08 and HC(S)12 devices.
 
0 Kudos
Reply

2,491 Views
PeterHouse
Contributor I
Beware of the I2C module.  I worked on a project two years ago using the GB60 and a Dallas DS2482-800 as the only two devices on the bus.  While working with the Dallas engineers we came upon an issue where the Dallas state machine and the GB60 were incompatible.  The GB60 would hang the SDA line low until a power cycle and there was no way to tell from the firmware what the problem was other than communications had stopped.  The I2C module was made for interrupt use only and if an event did not generate an interrup there was no way to poll the state of the I2C module for recovery information.

At the time, I could not get a freescale support engineer on the phone and could only communicate by email about once every day or so which was taking too long.  The GB60 is one of the first Freescale CPUs to have I2C and the I2C module was ported over from the S12.  The only sample cade was for the S12 which had slightly different naming conventions and slightly different signaling which made the code essentially useless. 

I was programming using Bytecraft C and ended up writing an I2C assembler bit bang library to handle the DS2482.   This works flawlessly.

I am sure this has been fixed since I reported it in detail with code samples and logic analyzer captures to the Freescale engineer I was in emailing at the time.

Good Luck,

Peter House
0 Kudos
Reply

2,491 Views
BasePointer
Contributor II
Hi Peter,
 
I think I2C Module of AW32 still has some problems. It is not working stabile, it work for first usage but doesn't for second and later... Exactly you mentioned, sometimes SDA line is hanged at low. I don't know why. In spite of setting whole I2C control byte(IICC) at a time, it sometimes doesn't generate start, stop or set IICIF flag.
 
I implemented my own software I2C routines without using I2C Module. I have 4 device on the bus, two EEPROMs, one RTC and one temperature measurement IC. All works flawlessly now.
 
PS: Suggested application note also didn't worked for me. I wonder why writter of this application note try to set SRW that was indicated as read only in the datasheet? I also would like to ask that what happens if slave on the bus can't send the ACK, while(RXAK)?
 
Regards,
BP.
0 Kudos
Reply

2,491 Views
JMAC
Contributor I
Hi folks.
I just burned the last week discovering the same thing on an AW60. I attempted to replace a previously working bit-bang routine with an LCD driver and EEPROM on the same IIC bus.  However, trying to run the IIC in a polled mode in combination with an RTI interrupt timer results in some very strange problems in the IIC module.  Perhaps its me, but the docs on working with this module are really poor.  I can get the RTI timer to run fine, and seperately, I can get the IIC to work fine most of the time, but I can never get them to run together with the IIC polled.  As much as I would love to hammer out the code details on this, I'm already behind because of this problem.   
0 Kudos
Reply

2,491 Views
PeterHouse
Contributor I
JMAC,

As I recall the IIC module on the GB60 did not have enough flags to run in polled mode.  There are interrupts with no way to tell if they fired without interrupt code.  I would never recommend running a module of this complexity in polled mode when a working interrupt mode is available.

Unfortunately, as far as I can tell, there is no working, reliable interrupt mode in the GB60 IIC peripheral and polling is not an option.

I do not know if the AW60 IIC module is the same as the GB60.  If you can run it polled then it must have more status flags available and is possibly a different module.  If your application is not CPU bound then I would consider a bit-bang approach.

I did not write a general purpose IIC module as I had only a single IIC device to with which to communicate.  Otherwise, I would offer my IIC code.

Peter House
0 Kudos
Reply

2,491 Views
JMAC
Contributor I
This is a late "thank you much" to PeterHouse for the feedback around 9/18/2007 on AW60 IIC.  I just scanned back through here today, and was a bit surprised at how much activity is still on this thread.  The length of this total thread alone should tell you something. 
 
Heres my two cents on the polling use of this IIC module on the AW60.  IIC is slick for me simply because of the two-wire use. I often use it for passing info across isolation barriers, and doing this with two optos instead of three for SPI is really nice.  I often don't actually "bus" anything on it - just one part like a DAC, an LCD, or an EEPROM.  However, as Peter said, it truly is a complex module in the AW60 for the few 2-3 bytes of data I jamb through.  In my case, running this in interrupt mode really makes no sense, as its far easier to simply wait for the bytes to clear and just move on in my specific application.  As I read through several other posts to the thread, I disagree on using interrupts any time just because they are available - if they don't make sense for the application code, then they don't make sense period.  In fact, throwing interrupts in everywhere for no good reason is a great way to build a pretty unreliable product.  The bit bang routines work best for these mini transfers (they have for over 10 years now on this actual product), so I went back to them after a week of messing around.  I had only tried to convert them because the new AW60 processor supported the IIC module. Honestly, I haven't had any problems for last 20 years working with simple bit-bang IIC implementations like this on
Mot/Freescale/TI/etc processors until I recently started playing with this AW60 module.  I'm a big fan of Freescale parts, and I was pretty disappointed this wouldn't work out.  
 
I find it odd sometimes in this forum when something clearly doesn't work in its basic described format, that the Freescale factory support is more of a debate on how a different approach certainly must be taken (ie. "don't run it in polling mode because it doesn't make any sense to do that when the code will be full of interrupts anyway")  What?  In this case, if the module contains proper flags to support simple monitoring of when data bytes clear (and it does), then it should work that way regardless of whether or not some other interrupt is running.  If not, maybe we need a errata to tell us what is going on. 
 
Thanks much to all the actual users out there like Peter that support this forum, and make it invaluable to all of us up in the middle of the night trying to sort these things out.       
0 Kudos
Reply

2,491 Views
Alban
Senior Contributor II
Hello JMAC,

"Freescale Factory Support" was NOT involved in this thread.
"Factory Support" is a special term used in supporting world which means L4 or 4th line.

Being "Freescaler" means being part of the company and wanting to help. The person could be less specialist than some 'external' members... But I would not refuse help as it gives another light on the matter.

In this case, the Freescaler who replied is knowledgable and see a lot of questions.


For very specific applications, interrupts are forbidden because the exact path of execution is required to be known. This is usually the case in safety critical systems. That is probably why polling is still offered.
With the growing number of features required and the always growing abilities to test better, the number of applications forbidding the use of interruption is falling.

As an example, MAGGALY an automatic subway was only made of logic, because there was a probability of 0.000001 of any microprocessor to crash (I don't know the odds now).


I would still advise you to use the interrupt driven mechanism...

Alban.
0 Kudos
Reply