[STM8] STM8S I2C Slave mode error resolution

1. Problem background

Use the I2C Slave mode on the STM8S platform , refer to the Sample Code of the STM8S standard library, but as long as the Master Controller Read/Write multiple Bytes, there will be a problem that the interrupt is triggered all the time. Because the I2C State Register corresponding to the interrupt is not correctly cleared, the interrupt has been triggered and the I2C communication fails.

Refer to the Sample Code path of the STM8S standard library as follows:
STM8S_StdPeriph_Lib\Project\STM8S_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange\Slave\

2. I2C Slave mode

The following is the reference code of STM8S I2C Slave mode . I have verified that there is no problem at present.

#define I2C_DATA_SIZE  8

#if ((I2C_DATA_SIZE > 0) && ((I2C_DATA_SIZE & (I2C_DATA_SIZE - 1)) != 0))
#error I2C_DATA_SIZE isnt a power of 2.
#endif


#define uint8_bits_def(x) union \
{\
	unsigned char x; \
	struct \
	{\
		unsigned char x##_Bit0:1, \
					  x##_Bit1:1, \
					  x##_Bit2:1, \
					  x##_Bit3:1, \
					  x##_Bit4:1, \
					  x##_Bit5:1, \
					  x##_Bit6:1, \
					  x##_Bit7:1; \
	};\
}

uint8_bits_def(tagI2C);
uint8_t i2c_addr = 0;
uint8_t i2c_data[I2C_DATA_SIZE] = {
    
    0x00};

void I2C_Slave_IRQHandler(void)
{
    
    
	volatile I2C_Event_TypeDef Event = I2C_GetLastEvent();

	/* Slave address matched with the address sent by master */
	/* EV1: ADDR = 1, 顺序读SR1,SR3寄存器清除此标志位 */
	if(Event == (I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED))
	{
    
    
		tagI2C_Bit0 = 1;
	}
	/* Slave received the data byte from master */
	/* EV2: RxNE = 1, 读DR寄存器清除此位 */
	else if(Event == (I2C_EVENT_SLAVE_BYTE_RECEIVED))
	{
    
    
		uint8_t ch = I2C_ReceiveData();
		if(tagI2C_Bit0){
    
    
			tagI2C_Bit0 = 0;
			i2c_addr = ch;
		}else{
    
    
			i2c_data[i2c_addr++ & (I2C_DATA_SIZE - 1)] = ch;
		}
	}
	/* Slave received STOP byte from master */
	/* EV4: STOPF = 1,读SR1寄存器后再写CR2清除 */
	else if(Event == (I2C_EVENT_SLAVE_STOP_DETECTED))
	{
    
    
		I2C_GetFlagStatus(I2C_FLAG_STOPDETECTION);
		I2C_GenerateSTOP(DISABLE);
	}
	/* SLAVE TRANSMITTER */
	/* Data transmited from slave to master */
	/* EV3: TxE = 1, 写DR寄存器清除DR */
	else if((Event == (I2C_EVENT_SLAVE_BYTE_TRANSMITTED)) ||
		     (Event == (I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED)))
	{
    
    
		uint8_t ch = i2c_data[i2c_addr++ & (I2C_DATA_SIZE - 1)];
		I2C_SendData(ch);
	}
	/* Acknowledge failure */
	/* EV3-2: AF = 1, AF is cleared by writing '0' in AF bit of SR2 register */
	else if(Event == (I2C_EVENT_SLAVE_ACK_FAILURE))
	{
    
    
		I2C_ClearFlag(I2C_FLAG_ACKNOWLEDGEFAILURE);
	}
}


void I2C_Slave_Init(void)
{
    
    
	I2C_DeInit();

	/* Initialize I2C peripheral */
	I2C_Init(400000, SLAVE_ADDRESS, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, 16);
	
	/* Enable Error Interrupt*/
	I2C_ITConfig((I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF), ENABLE);
}

[Remarks]: It I2C_Slave_IRQHandleris called in the stm8s_it.c file INTERRUPT_HANDLER(I2C_IRQHandler, 19).

3. Analysis and verification

In order to facilitate the verification of the problem, I2C_Slave_IRQHandlerall Events are saved in the function, as follows:

+uint16_t event_rx_buf[50] = {
    
    0x00};
+uint16_t event_count = 0;

void I2C_Slave_IRQHandler(void)
{
    
    
	volatile I2C_Event_TypeDef Event = I2C_GetLastEvent();

+	if(event_count < 50){
    
    
+		event_rx_buf[event_count++] = Event;
+	}

	...
}
  • The Event generated by writing 2 bytes on the Master side is as follows:
    Insert picture description here

    [Remarks] The screenshot above appears 3 times 0x240. Because it is 1个Register addr + 2个data, it actually writes 3 data.

  • The Event generated by reading 2 bytes on the Master side is as follows:
    Insert picture description here

    [Remarks] 0x680When sending data, no processing is done in the interrupt function, waiting for the sending to be completed.

Guess you like

Origin blog.csdn.net/ZHONGCAI0901/article/details/109184137