Search code examples
embeddedinterrupt-handlingi2cstm32slave

I2C slave receiver on stm32f4


I try to implement a i2c slave receiver interrupt service routine on a stm32f4. Here is my smart piece of code.

void I2C2_EV_IRQHandler()
  {
    switch (I2C_GetLastEvent(I2C2))
    {
    //The address sent by the master matches the own address of the peripheral
    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
        //The slave stretches SCL low until ADDR is
        //cleared and DR filled with the data to be sent
        I2C_ClearFlag(I2C2,I2C_FLAG_ADDR);
        break;

    //The application is expecting a data byte to be received
    case I2C_EVENT_SLAVE_BYTE_RECEIVED:
        I2C_ReceiveData(I2C2);
        break;

    //The application is expecting the end of the communication
    //Make sure that both ADDR and STOPF flags are cleared
    //if both are found set.
    case I2C_EVENT_SLAVE_STOP_DETECTED:
        if(I2C_GetFlagStatus(I2C2,I2C_FLAG_ADDR) == SET)
            I2C_ClearFlag(I2C2,I2C_FLAG_ADDR);
        if(I2C_GetFlagStatus(I2C2,I2C_FLAG_STOPF) == SET)
            I2C_ClearFlag(I2C2,I2C_FLAG_STOPF);
}

}

The interrupt becomes called and I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED case is entered. The SCL is low now. The reference manual says if I clear the address flag, the clock will continue and data will be sent (Page 579 - Slave receiver). In my opinion the interrupt always becomes called if any data arrives and next state will be I2C_EVENT_SLAVE_BYTE_RECEIVED.

I can not find any example from stm or via google. Can anybody help me or show me an example.


Solution

  • now it works. My problem was that I was not able to reset the ADDR and the STOPF register with the given commands out of reference manual. But if do it in a loop it works fine for me. Here my working Interrupt Routine.

     void I2C3_EV_IRQHandler()
     {
         switch (I2C_GetLastEvent(I2C3))
         {
    
        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
            STM_EVAL_LEDOn(LED3);
            STM_EVAL_LEDOff(LED5);
            break;
    
        case I2C_EVENT_SLAVE_BYTE_RECEIVED:
            STM_EVAL_LEDToggle(LED4);
            STM_EVAL_LEDOff(LED3);
            I2C_InputBuffer[I2C_InputBufferIndex++] = I2C_ReceiveData(I2C3);
            break;
    
        case I2C_EVENT_SLAVE_STOP_DETECTED:
            STM_EVAL_LEDOn(LED6);
            STM_EVAL_LEDOff(LED4);
            break;
        }
    
        I2C_CleanADDRandSTOPF();
    
        if(I2C_InputBufferIndex > MOTOR_PACKAGE_SIZE-1)
        {
          motorHandleEvent(I2C_InputBuffer);
          I2C_InputBufferIndex = 0;
          uint8_t resetIndex;
          for(resetIndex = 0; resetIndex < MOTOR_PACKAGE_SIZE; resetIndex ++)
            I2C_InputBuffer[resetIndex] = 0;
        }
    }
    
    inline void I2C_CleanADDRandSTOPF()
    {
      while ((I2C3->SR1 & I2C_SR1_ADDR) == I2C_SR1_ADDR)
      {
        volatile uint32_t temp;
        temp=I2C3->SR1;
        temp=I2C3->SR2;
      }
      while ((I2C3->SR1&I2C_SR1_STOPF) == I2C_SR1_STOPF)
      {
        volatile uint32_t temp;
        temp=I2C3->SR1;
        I2C3->CR1 |= 0x1;
      }
    }