cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_I2C_SlaveTxCpltCallback() is called despite not all bytes are sent?

mk528
Associate II

Hi,

I´m using an stm32f401 and observing suspicious behaviour on the I2C slave.

My issue is that I get transmit completed callback after master has read 1 byte, but I have called HAL_I2C_Slave_Seq_Transmit_IT to send 2 bytes.

I´m trying to send 2 bytes by calling:

HAL_I2C_Slave_Seq_Transmit_IT(&i2cHandle, data, 2, I2C_FIRST_FRAME);

Then I receive

HAL_I2C_SlaveTxCpltCallback(&i2cHandle);

Just after the host(I2C master) has read 1 byte.

I have checked that I2C_SlaveTransmit_TXE is called as 2 times for unknown reason.

I´m using raspberrypi as the I2C master and can reproduce the issue by calling (in the terminal)

i2ctransfer -y 1 r1@0xAddr

If I instead call the slave transmit api with data size as 3 bytes:

HAL_I2C_Slave_Seq_Transmit_IT(&i2cHandle, data, 3, I2C_FIRST_FRAME);

I will receive the callback after 2 bytes are read by the host.

Is this a known issue, or expected behaviour?

1 ACCEPTED SOLUTION

Accepted Solutions
mk528
Associate II

I think figured it out.

From Reference Manual:

"Note: TxE is not cleared by writing the first data being transmitted, or by writing data when BTF is set, as in both cases the data register is still empty."

So, what happens is that Slave goes into to transmission mode, TxE is set high, I2C_SlaveTransmit_TXE is called once and writing to DR, immediately after (approx 5.5 us later), a second event IRQ occurs since TxE is not cleared by the first write to DR and I2C_SlaveTransmit_TXE is called again, but this time TxE is cleared.

So it is by hardware design that the driver has to send 2 bytes after a start condition. Probably makes sense if the first write goes to the DR, and second write pushes it to the Data shift register, which means 2 writes are necessary to put the first byte into the SDA line.

View solution in original post

3 REPLIES 3
mk528
Associate II

Hi again,

How is going, anyone having any idea?

I have also observed that I get the HAL_I2C_SlaveTxCpltCallback(&i2cHandle) callback also when reading 0 bytes from raspberrypi.

    i2ctransfer -y 1 r0@0xAddr

I´m getting 2 I2C event interrupts where TxE bit is set i.e I2C_SlaveTransmit_TXE is called twice.

So I get 2 TxE I2C event interrupts regardless of master reading 0, 1 or 2 bytes. How come?

Our implementation does call :

HAL_I2C_Slave_Seq_Transmit_IT(&i2cHandle, data, 2, I2C_FIRST_FRAME);

in the interrupt handler hook for address:

HAL_I2C_AddrCallback(hi2c, TransferDirection, SlaveAddrCode);

We are using the STM32 driver generated from MXCube with version:

FirmwarePackage=STM32Cube FW_F4 V1.25.2

mk528
Associate II

I have made a hack to set a debug pin when TxE bit is set during an interrupt, and clear the debug pin when TxE bit is cleared after DR is written.

I can see that TxE toggles 2 times when host reads 2 bytes, but it only toggles 1 time when host reads 1 byte or 0 byte.

Attaching screenshots from logic analyzer capture. (Channel 3 is the debug pin reflecting TxE bit)0693W00000NqThtQAF.png0693W00000NqThoQAF.png0693W00000NqThjQAF.pngSo I really don´t understand why I receive 2 I2C_SlaveTransmit_TXE callbacks when reading 0 or 1 byte now.

mk528
Associate II

I think figured it out.

From Reference Manual:

"Note: TxE is not cleared by writing the first data being transmitted, or by writing data when BTF is set, as in both cases the data register is still empty."

So, what happens is that Slave goes into to transmission mode, TxE is set high, I2C_SlaveTransmit_TXE is called once and writing to DR, immediately after (approx 5.5 us later), a second event IRQ occurs since TxE is not cleared by the first write to DR and I2C_SlaveTransmit_TXE is called again, but this time TxE is cleared.

So it is by hardware design that the driver has to send 2 bytes after a start condition. Probably makes sense if the first write goes to the DR, and second write pushes it to the Data shift register, which means 2 writes are necessary to put the first byte into the SDA line.