This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LAUNCHXL-F28069M: I2C master receiver - interrupt i2c_int1a_isr doesn't work

Part Number: LAUNCHXL-F28069M
Other Parts Discussed in Thread: DRV8301, DRV8305

Hi 

I run my code (reading data from I2C sensor) inside proj_lab12b, and it works, but after a while transmission break down. Sometimes it works about 30 seconds sometimes only 2 seconds, sometimes about 15..

If I run debug mode, communication with computer also has problems - from the moment when I2C stops working, changing the enableSys or Run_Identify flag  does not give the effect of stopping the motor. Other variables in watchwindow stops refreshing they values, only st_obj.vel.conv.Pos_erev still refresh. 

My code is in the main loop. Works in non-FIFO mode, master-receiver, no interrupts. I think changing to the interrupts mode can fix the problem of breaking the connection.

So i try to enable i2c_int1a_isr, but it doesn't work.

To enable i2c_int1a_isr, I made the following changes:

in hal.h 

// the globals
extern interrupt void mainISR(void);
extern interrupt void i2c_int1a_isr(void);//my changes

  /*
  .
  .
  .
  */
  
  static inline void HAL_initIntVectorTable(HAL_Handle handle)
 {
  HAL_Obj *obj = (HAL_Obj *)handle;
  PIE_Obj *pie = (PIE_Obj *)obj->pieHandle;


  ENABLE_PROTECTED_REGISTER_WRITE_MODE;

  pie->ADCINT1 = &mainISR;
  pie->I2CINT1A = &i2c_int1a_isr; //my changes

  DISABLE_PROTECTED_REGISTER_WRITE_MODE;

  return;
 } // end of HAL_initIntVectorTable() function

in main.h:

interrupt void mainISR(void);

interrupt void i2c_int1a_isr(void); //my changes

and proj_lab12b.c :

#ifdef FLASH
#pragma CODE_SECTION(mainISR,"ramfuncs");
#pragma CODE_SECTION(i2c_int1a_isr,"ramfuncs"); 
#endif

  /*
  .
  Motorware code here
  .
  */

void main(void)
{
  /*
  .
  .
  Motorware init code here
  .
  .
  */

  PIE_enableInt(halHandle->pieHandle,PIE_GroupNumber_8,PIE_InterruptSource_I2CA1 ); //enable interrupt
  CPU_enableInt(halHandle->cpuHandle,CPU_IntNumber_8);

    i2c_cycle=0;

    I2caRegs.I2CSAR = 0x0068;       // Slave address - EEPROM control code
    I2caRegs.I2CPSC.all = 35;        // Prescaler - need 7-12 Mhz on module clk
    I2caRegs.I2CCLKL = 10;          // NOTE: must be non zero
    I2caRegs.I2CCLKH = 5;           // NOTE: must be non zero
	
    I2caRegs.I2CMDR.all = 0x0020;

    I2caRegs.I2CSAR = 0x68;                         //Set slave address
    I2caRegs.I2CCNT = 2;                            //Set count to 5 characters plus 2 address bytes
    I2caRegs.I2CDXR = 0x6B;                         //register where i will write 0x00
    I2caRegs.I2CMDR.bit.TRX = 1;                    //Set to Transmit mode
    I2caRegs.I2CMDR.bit.MST = 1;                    //Set to Master mode
    I2caRegs.I2CMDR.bit.FREE = 1;                   //Run in FREE mode
    I2caRegs.I2CMDR.bit.STP = 1;                    //Stop when internal counter becomes 0
    I2caRegs.I2CMDR.bit.STT = 1;                    //Send the start bit, transmission will follow

    while(I2caRegs.I2CSTR.bit.XRDY == 0){};         //Do nothing till data is shifted out
    I2caRegs.I2CDXR = 0x00;

  
	I2caRegs.I2CIER.all = 0x18;     // Enable xrdy and rrdy interrupts
  
  for(;;)
  {

	while(gMotorVars.Flag_enableSys)
		{
			
		/*
		.
		.
		Motorware loop code here
		.
		.
		*/  
		  
		i2c_cycle++;

		if(i2c_cycle==200)
		{
			i2c_cycle=0;

			I2caRegs.I2CSAR = 0x68;                      //Set slave address
			I2caRegs.I2CCNT = 1;                         //Set count to 2 address bytes
			I2caRegs.I2CDXR = 0x3B;                      //Send high address of register to read
			I2caRegs.I2CMDR.bit.TRX = 1;                 //Set to Transmit mode
			I2caRegs.I2CMDR.bit.MST = 1;                 //Set to Master mode
			I2caRegs.I2CMDR.bit.FREE = 1;                //Run in FREE mode
			I2caRegs.I2CMDR.bit.STP = 0;                 //Dont release the bus after Tx
			I2caRegs.I2CMDR.bit.STT = 1;                 //Send the start bit, transmission will follow

		}

    } // end of while(gFlag_enableSys) loop

  } // end of for(;;) loop

} // end of main() function



__interrupt void i2c_int1a_isr(void)
{
   uint16_t IntSource;
   //
   // Read interrupt source
   //
   IntSource = I2caRegs.I2CISRC.all;

   if(RxdData_counter>5)RxdData_counter=0;

   if(IntSource == 0x0005)  // XRDYINT
   {
       
       I2caRegs.I2CCNT = 6;                         //read 6 bytes from sensor
       I2caRegs.I2CMDR.bit.TRX = 0;                 //Set to Recieve mode
       I2caRegs.I2CMDR.bit.MST = 1;                 //Set to Master mode
       I2caRegs.I2CMDR.bit.FREE = 1;                //Run in FREE mode
       I2caRegs.I2CMDR.bit.STP = 1;                 //Stop when internal counter becomes 0
       I2caRegs.I2CMDR.bit.STT = 1;                 //Repeated start, Reception will follow
       
   }
   else if(IntSource == 0x0004)  // RRDYINT
   {
       
       RxdData[RxdData_counter] = I2caRegs.I2CDRR;
       RxdData_counter++;							//I want to read 6 bytes, and write them to RxdData[0],RxdData[1],RxdData[2]..
	   
       I2caRegs.I2CSTR.bit.RRDY = 1;				//SPRUH18G page 921 "RRDY is manualy cleared. To clear this bit write 1 to it."
       
   }
   else
   {
       //
       // Generate some error due to invalid interrupt source
       //
       __asm("   ESTOP0");
   }

   //
   // Enable future I2C (PIE Group 8) interrupts
   //
   PIE_clearInt(halHandle->pieHandle,PIE_GroupNumber_8);

}

What else can I do to make interrupt i2c_int1a_isr work?

Regards,

Wojciech

  • So you aren't getting any I2C interrupts at all? How are you checking? Breakpoint in the ISR? If you force the interrupt by writing to the corresponding PIEIFR bit (just to test that you have all the necessary enable bits set), do you get into your ISR?

    If you look at the I2C registers in the CCS registers view, what is the status of the bits in I2CSTR?

    Whitney
  • Hi 

    Thank You for your reply

    I checked it using an logic analyzer - I did not see the effects of the code contained in this interrupt.

    I also checked it by breakpoint in  i2c_int1a_isr - the program did not stop.

    When the program ran, I checked the PIE registers:

    PIEIER8 = 0x0001

    PIEIFR8 = 0x0000

    So I write 0x0001 to PIEIFR8 and breakpoint in i2c_int1a_isr stops the program - the interruption occured.

    I2CSTR:
    When program starts:
    0001 0100 0011 0100b
    after 15 sec:
    0001 0100 0011 0110b
    for one second shows
    0001 0100 0011 0010b
    and again same as #2
    0001 0100 0011 0110b

    when I write 1 to PIEIFR8 and program stops at breakpoint (line 115 in the above code) inside i2c_int1a_isr :
    0000 0100 0011 0000b

  • Instead of using XRDY, try using ARDY to determine that you're ready to transmit data. Also, I see the NACK bit is getting set, but I don't see any code to handle it. Check out some of the advice on this page: processors.wiki.ti.com/.../I2C_Tips

    Whitney
  • Thank You

    Now transmission works and I can watch it on logic analyzer:

    But when I set on Run_Identify flag, BOOSTXL-DRV8301 (motor driver) turns on, and sometimes transmission break down (becouse of electromagnetic radiation/noise i think)

    And I2C_STR 0001 0100 0010 0001b 

    It looks like nack bit is getting set in registry 

    And looks like: External Slave Device Hanging the Bus by Holding SDA Low scenario from i2c_tips

    I want to use the solution: By configuring the I2C for "free data format" and then reading a byte the I2C will immediately start sending clocks to input data (rather than trying to send an address). This can be used to free up the bus.

    Can I use this solution in if(nack){...} interrupt? Or should I check additional conditions? (SDA low/busy)

    Is my handling-NACK code correct?

    My code:

    __interrupt void i2c_int1a_isr(void)
    {
       uint16_t IntSource;								// Read interrupt source 
       IntSource = I2caRegs.I2CISRC.all;
       if(RxdData_counter>5)RxdData_counter=0;
    
       if(IntSource == 0x0002)  			// NACKINT
       {
           I2caRegs.I2CMDR.bit.STP = 1;
           I2caRegs.I2CSTR.all = 0x0002;
    	   
    
       }
       else if(IntSource == 0x0003)  		// ARDYINT
       {
    
           I2caRegs.I2CCNT = 6;                         //read 6 bytes from sensor
           I2caRegs.I2CMDR.bit.TRX = 0;                 //Set to Recieve mode
           I2caRegs.I2CMDR.bit.MST = 1;                 //Set to Master mode
           I2caRegs.I2CMDR.bit.FREE = 1;                //Run in FREE mode
           I2caRegs.I2CMDR.bit.STP = 1;                 //Stop when internal counter becomes 0
           I2caRegs.I2CMDR.bit.STT = 1;                 //Repeated start, Reception will follow
           
           I2caRegs.I2CSTR.bit.ARDY = 1;				//SPRUH18G p.911 "The ARDY, RRDY, and XRDY bits in I2CSTR are not cleared when I2CISRC is read"
    
       }
       else if(IntSource == 0x0005)  		// XRDYINT
       {
           I2caRegs.I2CSTR.bit.XRDY = 1;				//SPRUH18G p.911 "The ARDY, RRDY, and XRDY bits in I2CSTR are not cleared when I2CISRC is read"
       }
       else if(IntSource == 0x0004)  		// RRDYINT
       {
    
           RxdData[RxdData_counter] = I2caRegs.I2CDRR;
           RxdData_counter++;                           //I want to read 6 bytes, and write them to RxdData[0],RxdData[1],RxdData[2]..
           
           I2caRegs.I2CSTR.bit.RRDY = 1;                //SPRUH18G p.911 "The ARDY, RRDY, and XRDY bits in I2CSTR are not cleared when I2CISRC is read"
       }
       else
       {
           __asm("   ESTOP0");
       }
       PIE_clearInt(halHandle->pieHandle,PIE_GroupNumber_8);
    }

    Regards, 

    Wojciech

  • That looks fine. It might be helpful to do if((IntSource == 0x2) || (I2CSTR.NACK == 1)) instead. I don't know how the ISRC register prioritizes the interrupt sources, but that might be a good way to make sure you handle the NACK first.

    Another thing to think about is that since several of the bits in I2CSTR are write-1-to-clear, the read-modify-write generated by a statement like I2caRegs.I2CSTR.bit.ARDY = 1 will clear the other status flags if they are set as well. This may not be a big deal for the way you're using them, but it's something to keep in mind.

    Is your code working reliably now? Do you need more assistance on this or can I close the thread?

    Whitney
  • Hi
    Thank You very much for help.
    I changed driver from drv8301 to drv8305 and now it works. It looks like drv8301 produces electromagnetic noises, too strong for i2c transmission.
    I will apply your tips in my project.
    You can close the thread.

    Regards,
    Wojciech