Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix transmission termination in I2C DMA master read. #736

Merged
merged 2 commits into from
Feb 2, 2024

Conversation

zyma98
Copy link
Contributor

@zyma98 zyma98 commented Feb 2, 2024

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 I2C stop 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.

image

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 the dr 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.

image

The bug can be fixed simply by setting the last control bit when it is required by STM32 reference manual RM0090.

Set the `last` control bit in I2C when the read length is larger or equal to 2 and when using DMA in master mode.
@burrbull burrbull added this pull request to the merge queue Feb 2, 2024
Merged via the queue into stm32-rs:master with commit 5337975 Feb 2, 2024
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants