Frage

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.

War es hilfreich?

Lösung

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;
  }
}

Andere Tipps

The hardware is doing clock stretching to ensure that the slave is keeping up with the master. The slave first waits to get an address match. Then you get interrupt while SCL is held low. This allows slave to basically provide flow control to the master. The master detects that SCL is being held low by slave and it will wait for it to be released before master sends any more data. So you won't get additional interrupts on data being received because the master won't send any more data until you let SCL go high. You can read about clock stretching here http://en.wikipedia.org/wiki/I%C2%B2C

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top