关于HAL_I2C_Master_Transmit函数每次循环发2字节的疑问
Great question—this is a clever piece of hardware optimization in the STM32 HAL library, and it all boils down to leveraging the I2C peripheral's Byte Transfer Finished (BTF) flag to boost transmission efficiency. Let’s break it down step by step:
First, What’s the BTF Flag?
The I2C_FLAG_BTF isn’t just a "byte sent" indicator—it signals two key things:
- The data in the I2C Data Register (
DR) has been completely shifted out onto the bus. - The
DRregister is empty and the peripheral is fully ready for new data.
Compare that to the TXE flag (which we wait for first): TXE only tells us the DR is empty—it doesn’t confirm the previous byte has finished transmitting (the shift register might still be sending it).
Why Send Two Bytes in One Loop Iteration?
This logic is all about minimizing idle time on the I2C bus and cutting down software overhead. Here’s why it matters:
- Maximize bus utilization: When
BTFis set, the I2C peripheral is in a "ready to go" state with no pending data in the shift register. Writing a second byte immediately lets the hardware start transmitting it without any gap after the first byte. If we waited for the next loop iteration to send the second byte, we’d introduce unnecessary idle time while the software rechecks flags. - Reduce software loop overhead: By handling two bytes per loop when possible, we cut down on the number of times the software has to wait for flags, update counters, and iterate through the loop. This makes the overall transmit function faster and more efficient.
- Leverage hardware behavior: The STM32 I2C peripheral is designed to support back-to-back writes when
BTFis set. The HAL library is just taking advantage of this built-in hardware feature to optimize performance.
Walk Through the Code Logic
Looking at the loop in your snippet:
- We first wait for
TXEto be set, write one byte toDR, and decrement our transfer counters. - Then we check if
BTFis set and we still have bytes left to send. If both are true:- We immediately write the next byte to
DR(no need to wait forTXEagain—BTF already confirms the peripheral is ready). - Decrement the counters again for this second byte.
- We immediately write the next byte to
- Finally, we wait for
BTFto be set, which confirms both bytes (if we sent two) have finished transmitting before moving to the next loop iteration.
Edge Case: What if Only One Byte is Left?
The check hi2c->XferSize != 0U ensures we don’t try to send a second byte when there’s nothing left to transmit. For example, if we have 1 byte remaining after the first write, this condition fails, and we just wait for BTF to confirm that last byte was sent before exiting the loop.
To Sum It Up
This isn’t a redundant check—it’s a deliberate optimization to use the I2C peripheral’s capabilities to the fullest. By sending two bytes back-to-back when the hardware is ready, the HAL library minimizes bus idle time and software overhead, making the I2C transmit operation as efficient as possible.
内容的提问来源于stack exchange,提问作者SajadGD

