cancel
Showing results for 
Search instead for 
Did you mean: 

how to terminate I2C master-receive transaction?

Csen.1
Associate II

target CPU: STM32F427IG

I set up STM32F427IG as master receiver via DMA.

I wait on "DMA_GetFlagStatus(I2Cx_DMA_STREAM_RX, I2Cx_RX_DMA_TCFLAG" to figure out if I received what was sent.

After running for 20 minutes or so, I2Cx_RX_DMA_TCFLAG flag does not get set within the timeout period I had defined.

When I2Cx_RX_DMA_TCFLAG does not get set within my timeout period, I want to cancel this transaction. To terminate this transaction I believe I need to send Nack to the transmitter and then generate stop condition.

So far my attempts failed.

Based on TRM, this is what I do:

if(TimeOut ) {

   I2C_DMACmd(I2Cx, DISABLE);   

   DMA_Cmd(I2Cx_DMA_STREAM_RX, DISABLE);

    

   (void)I2C_ReceiveData(I2Cx);

   I2C_AcknowledgeConfig(I2Cx, DISABLE);

   I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Next);

   I2C_GenerateSTOP(I2Cx, ENABLE);

   (void)I2C_ReceiveData(I2Cx);

  }

How could I achieve my goal?

thank you in advance

3 REPLIES 3
Csen.1
Associate II

btw, I see that I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) is true, so STM gets the flag that it is in master-receiver mode.

Piranha
Chief II

I2C peripheral has a software reset bit, which resets the whole internal state machine, but doesn't reset the configuration.

Csen.1
Associate II

Thank you, Piranha.

I am utilizing s/w reset bit as you suggested. and to make life easy, I commented out all I2C related receive or transmit calls on slave MCU.

when timeout occurs below, I generate stop condition and then call I2C_SoftwareResetCmd.

then I check busy flag. result = reset, meaning not busy

then I check master/slave mode flag, result = reset, meaning slave.

so, the flags indicate success to me.

right after, I want to reinit I2C and generate start condition. It fails, please see the second code snippet.

case  MS_RX_WAIT_RX_EVENT: 
    while( (!DMA_GetFlagStatus(I2Cx_DMA_STREAM_RX, I2Cx_RX_DMA_TCFLAG)) &&
          (TimeOut != 0) ){};
    
    if(TimeOut == 0) { 
      i2c_state = MS_GENERATE_START; 
 
      I2C_DMACmd(I2Cx, DISABLE);    
      DMA_Cmd(I2Cx_DMA_STREAM_RX, DISABLE);
 
      I2C_GenerateSTOP(I2Cx, ENABLE);
 
      I2C_SoftwareResetCmd(I2Cx, ENABLE);
 
      TimeOut = 1; // do we need to give time to reset to complete? any flag to check?
      while(TimeOut != 0){}
      FlagStatus status = I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY); // reset
      status = I2C_GetFlagStatus(I2Cx, I2C_FLAG_MSL);      // reset
      return;

...

I2C_Cmd(I2Cx, ENABLE);
    
  I2C_DeInit(I2Cx);
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  I2C_InitStructure.I2C_OwnAddress1 = SLAVE_ADDRESS;
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
  I2C_Init(I2Cx, &I2C_InitStructure);
 
I2C_GenerateSTART(I2Cx, ENABLE);
 
TimeOut = 200;
 i2c_state++;
    
case MS_MODE_TX_SELECTED:
    while((!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)) &&
          (TimeOut !=0)) 
    {};
    
    if(TimeOut == 0)  // rework
    {      
      ...

any feedback on why generating start condition fails, why I2C_EVENT_MASTER_MODE_SELECT does not happen.