AnsweredAssumed Answered

I2C interrupt driven communication problem!

Question asked by pacman on Dec 11, 2014
Hello friends!

I'm using I2C1 on a STM32F103CB, according to AN2824 and reference manual. My goal is to use I2C with lower priority interrupts. For that purpose, i dont use ITBUF, but only ITEVT interrupt.

The i2cWrite routine enables ITEVT, issues START,
-Then program enters ISR with SB;I only read SR1, write slave address (with lsb clear),
-then enters ISR with ADDR; I read SR1 then SR2, write data byte to DR,
-then enters ISR with BTF; I read SR1, issue STOP end disable ITEVT,
Works fine!

The i2cRead routine enables ITEVT, issues START,
-Then program enters ISR with SB;I only read SR1, write slave address (with lsb set),
then no more interrupt enters! No watchdow, no hardfault, no xfault, just hangs!!!

The whole i2c code runs alone, before any other routine or interrupt starts. Btw I cant debug the board. The simplified code is below;
_____________________________________________
ErrorStatus I2C_Master_BufferRead(I2C_TypeDef* I2Cx, uint8_t* pBuffer, uint32_t NumByteToRead, I2C_ProgrammingModel Mode, uint8_t SlaveAddress, uint32_t Timeout){
    I2Cx->CR2 |= I2C_IT_EVT;
    I2CDirection = I2C_DIRECTION_RX;
    Buffer_Rx1 = pBuffer;
    SlaveAddress |= OAR1_ADD0_Set;
    Address = SlaveAddress;
    NumbOfBytes1rx = NumByteToRead;
    NumbOfBytes1tx = 0;
    /* Send START condition */
    I2Cx->CR1 |= CR1_START_Set;
    while(((I2Cx->CR2 & I2C_IT_EVT)!=0) && Timeout){
      Timeout--;
    }
    /* Wait until BUSY flag is reset (until a STOP is generated) */
    while ((I2Cx->SR2 & 0x0002) == 0x0002 && Timeout)
    {
      Timeout--;
    }
    /* Enable Acknowledgement to be ready for another reception */
    I2Cx->CR1 |= CR1_ACK_Set;
    if (Timeout == 0){
      return ERROR;
    }
  return SUCCESS;
}
________________________________________
void i2cISR(void){
  __IO uint32_t SR1Register = 0;
  __IO uint32_t SR2Register = 0;
  SR1Register = I2C1->SR1;
  /* If SB = 1, I2C1 master sent a START on the bus: EV5) */
  if ((SR1Register & 0x0001) == 0x0001)//-- SB
  {
    /* Send the slave address for transmssion or for reception (according to the configured value
     in the write master write routine */
    I2C1->DR = Address;
    SR1Register = 0;
    SR2Register = 0;
  }
    /* If ADDR = 1, EV6 */
    if ((SR1Register & 0x0002) == 0x0002)//-- ADDR
    {
        /* Initialize Receive counter */
        Rx_Idx1 = 0;
        if (NumbOfBytes1rx == 1)
        {
          __disable_irq();
          NumbOfBytes1rx--;
          I2C1->CR1 &= CR1_ACK_Reset;
          SR2Register = I2C1->SR2;
          I2C1->CR1 |= CR1_STOP_Set;
          __enable_irq();
        }else{
            I2C1->CR2 &= (uint16_t) ~I2C_IT_EVT;
            /* Configure I2C1 DMA channel */
            I2C_DMAConfig(I2C1, Buffer_Rx1, NumbOfBytes1rx, I2C_DIRECTION_RX);
            /* Set Last bit to have a NACK on the last received byte */
            I2C1->CR2 |= CR2_LAST_Set;
            /* Enable I2C DMA requests */
            I2C1->CR2 |= CR2_DMAEN_Set;
            //-- Clear ADDR reading SR2.
            SR2Register = I2C1->SR2;
        }
      SR1Register = 0;
      SR2Register = 0;
    }
    if(NumbOfBytes1rx == 0){
      /* Read the data register */
      Buffer_Rx1[Rx_Idx1++] = I2C1->DR;
      /* Disable the BUF IT */
      I2C1->CR2 &= (uint16_t) ~I2C_IT_BUF;
      /* Disable EVT IT In order to not have again a BTF IT */
      I2C1->CR2 &= (uint16_t) ~I2C_IT_EVT;
    }else{
        while(1){
            __NOP();//-- trap.
        }
    }
    SR1Register = 0;
    if(SR2Register)
    SR2Register = 0;
}
________________________________________

Could you please help?
Thank you!

Outcomes