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.

I2C with Interrupts

Other Parts Discussed in Thread: HALCOGEN

Hello people,

I am trying to implement an I2C communication using interrupts. I want just to use Receive-data-ready interrupt and Transmit-data-ready interrupt. Unfortunately, they are not triggered as I was supposed them to do. I am using HalCoGen to generate the code. I have mapped the I2C interrupt to channel 62, I have enabled ICRRDY and ICXRDY in the I2C tab.

My initial goal is to send one byte and to receive one (using the interrupts), but the problem is that they do not look to be triggered at all. I have placed a breakpoint in my i2cInterrupt function and it does not reach this point. On the other hand, the right flags are set in the Interrupt Mask Register.

Let's say that I want an interrupt to be triggered when I send one byte successfully. I use this piece of code:

void main(void)
{
/* USER CODE BEGIN (3) */

	i2cInit();
	_enable_IRQ();
	i2cSetSlaveAdd(i2cREG1, ADXL345Addr);



  while(1)
  {
	 i2cSetMode(i2cREG1, I2C_MASTER);
	 i2cSetDirection(i2cREG1, I2C_TRANSMITTER);
	 i2cSetCount(i2cREG1, 1);
	 i2cSetStart(i2cREG1);
	 i2cSend(i2cREG1, 1, data_in);
  }


/* USER CODE END */
}

What am I missing???

I attach this simple project in case you need to check anything else. I would really appreciate any suggestions, cause I am struggling for many days with this issue.

Kind regards,
Stelios
7271.i2c_Int.zip

  • Hello again,

    I hope that I will not continue to write alone here. :-)

    After many experiments, the following piece of code does my job. But I would like to understand how it really works:

    void main(void)
    {
    /* USER CODE BEGIN (3) */
    
    	// Three axis variables
    	sint16 x, y, z= 0;
    	// Initialize the I2C module
    	i2cInit();
    
    	_enable_IRQ();
    
    	// Set the address of the slave device
    	i2cSetSlaveAdd(i2cREG1, ADXL345Addr);
    
    	i2cREG1->MDR = 0;
    	i2cREG1->MDR |= I2C_MASTER | I2C_TRANSMITTER | I2C_RESET_OUT;
    	i2cSetCount(i2cREG1, 3);
    	i2cSetStart(i2cREG1);
    	i2cSend(i2cREG1, 3, data_out);
    	while(dataReady == 0);
    	dataReady = 0;
    
    	i2cREG1->MDR = 0;
    	i2cREG1->MDR |= I2C_MASTER | I2C_RECEIVER | I2C_RESET_OUT;
    	i2cSetCount(i2cREG1, 1);
    	i2cSetStart(i2cREG1);
    	i2cReceive(i2cREG1, 1, &data_in[6]);
    	while(dataReady == 0);
    	dataReady = 0;
    
    	while(1);
    
    /* USER CODE END */
    }


    Why does it work when I setCount to 3? I am just sending one Byte!!! The screenshot of my analyzer:



    I have to note that I set dataReady flag equal to 1 in i2cNotification function. 

    I would be grateful if someone could explain me why this code works for me. :-)

    Kind regards,
    Stelios

  • Stelios,

    I added comments next to your functional calls to illustrate work functionality is performed. You can also check the source codes for those functions for more detail.

    i2cREG1->MDR = 0;
    i2cREG1->MDR |= I2C_MASTER | I2C_TRANSMITTER | I2C_RESET_OUT; //set up I2C modes
    i2cSetCount(i2cREG1, 3); //set up the count register so that the stop condition will be automatically generated after 3 bytes is transferred.
    i2cSetStart(i2cREG1); //generate the start condition
    i2cSend(i2cREG1, 3, data_out); //if in interrupt mode, write the first data, enable I2C module to generate TX interrupt. Otherwise, send data in polling mode.
    while(dataReady == 0);
    dataReady = 0;
    i2cREG1->MDR = 0;
    i2cREG1->MDR |= I2C_MASTER | I2C_RECEIVER | I2C_RESET_OUT; //set up I2C modes
    i2cSetCount(i2cREG1, 1); //set up the count register so that the stop condition will be automatically generated after 1byte is received.
    i2cSetStart(i2cREG1); //generate the start condition
    i2cReceive(i2cREG1, 1, &data_in[6]); // If in interrupt mode, clear interrupt flags, and set up parameters for ISR. Otherwise, receive data in polling mode.
    while(dataReady == 0);
    dataReady = 0;

    Thanks and regards,

    Zhaohong
  • Hello Zhaohong,

    Thank you for your comments. Though, if you can see in my analyzer's screenshot, I send just one Byte (not three that are specified in the send function). This is what I want, but I cannot understand why it does not work when I set

       i2cSetCount(i2cREG1, 1);

       i2cSetStart(i2cREG1);

       i2cSend(i2cREG1, 1, data_out);

    Actually when I set it as above, the interrupt is NOT triggered (Does not reach the breakpoint that I set in i2cInterrupt function).

    Knd regards,
    Stelios

  • Stelios,

    CPU sends the first tx byte in i2cSend() function. No interrupt is needed if your message has only one byte. Please check the source code in i2c.c for more details.

    Thanks and regards,

    Zhaohong
  • What I was missing probably, was the use of I2C_ARDY_INT interrupt between consecutive operations. I assume that the registers were not ready when I was trying to change mode and as a result my communication was faulty.  

    In any case, I attach my project which works well for an i2c Communication in Interrupt mode with the ADXL345 accelerometer. I hope it will be useful for someone in the future.

    Thanks and regards,

    Stelios

    0815.i2c_Int.zip