Fix transmission termination in I2C DMA master read. #736
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
We should set the
last
control bit in I2C when the read length is larger than or equal to 2 and when using DMA in master mode.Failing to set the
last
bit leads to elusive bugs that will be revealed only when the system is under some stress. In the following example, the I2C and DMA is configured to read 6 bytes from a peripheral.When the
last
bit is not set, the I2C interface will not respond the peripheral with NACK after receiving the 6th byte, causing the peripheral to continue to transmit the 7th byte. The DMA interrupt, however, will be triggered after receiving the 6th byte. When the system is not under stress, the DMA interrupt will get served promptly. Inside the ISR the I2Cstop
bit will be programed, causing the peripheral to terminate the transmission. Even though the I2C master receives one more byte than requested by the user code, it will not get stuck in this case. The sequence is shown with the following figure.In contrast, when the system is under stress, the DMA interrupt will not be served promptly, e.g., when there exists other higher priority interrupts. In this case, the peripheral continues to transmit the 7th and 8th byte. However, since the DMA has stopped fetching bytes from the I2C
dr
register after receiving the 6th byte, the 7th bytes will stay in thedr
register while the 8th byte stay in the shift-in register.The I2C bus will get stuck after reaching this condition. Now the I2C master interface will be stretching the SCL line to low to prevent the peripheral from sending any more bit, while the peripheral is holding the SDA line trying to send more bit. Since the peripheral is controlling SDA line, the I2C master has no way to send a stop condition by raising SDA to high. The following figure shows the transmission on the I2C bus before it gets stuck.
The bug can be fixed simply by setting the
last
control bit when it is required by STM32 reference manual RM0090.